@tonybfox/threejs-tools 1.0.5 → 1.0.7

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.
Files changed (41) hide show
  1. package/dist/asset-loader/index.cjs +3 -417
  2. package/dist/asset-loader/index.mjs +1 -6
  3. package/dist/camera/index.cjs +1 -393
  4. package/dist/camera/index.mjs +1 -6
  5. package/dist/chunk-4O4ENFL7.mjs +83 -0
  6. package/dist/chunk-55YVGK52.mjs +1 -0
  7. package/dist/chunk-B75TYEOO.mjs +44 -0
  8. package/dist/chunk-CLSRN5D2.mjs +1 -0
  9. package/dist/chunk-EQRUOKFV.mjs +1 -0
  10. package/dist/chunk-JRJBW66X.mjs +1 -0
  11. package/dist/chunk-OJFYE56U.mjs +1 -0
  12. package/dist/chunk-WZ4X7GQ2.mjs +1 -0
  13. package/dist/chunk-Z5VL3O6M.mjs +43 -0
  14. package/dist/compass/index.cjs +3 -304
  15. package/dist/compass/index.mjs +1 -6
  16. package/dist/grid/index.cjs +3 -159
  17. package/dist/grid/index.mjs +1 -6
  18. package/dist/index.cjs +7 -5406
  19. package/dist/index.mjs +1 -384
  20. package/dist/measurements/index.cjs +1 -1197
  21. package/dist/measurements/index.mjs +1 -8
  22. package/dist/sunlight/index.cjs +1 -440
  23. package/dist/sunlight/index.d.mts +19 -0
  24. package/dist/sunlight/index.d.ts +19 -0
  25. package/dist/sunlight/index.mjs +1 -6
  26. package/dist/terrain/index.cjs +1 -422
  27. package/dist/terrain/index.mjs +1 -6
  28. package/dist/transform-controls/index.cjs +1 -1586
  29. package/dist/transform-controls/index.mjs +1 -12
  30. package/dist/view-helper/index.cjs +1 -435
  31. package/dist/view-helper/index.mjs +1 -6
  32. package/package.json +1 -1
  33. package/dist/chunk-2CDI7ORN.mjs +0 -163
  34. package/dist/chunk-FBTT6MU6.mjs +0 -386
  35. package/dist/chunk-IAZH4OHC.mjs +0 -399
  36. package/dist/chunk-LUE7VHLK.mjs +0 -422
  37. package/dist/chunk-OZKJ3GAD.mjs +0 -1160
  38. package/dist/chunk-W4DAAAW6.mjs +0 -404
  39. package/dist/chunk-XA7OKYSM.mjs +0 -357
  40. package/dist/chunk-YMMLYGHV.mjs +0 -1578
  41. package/dist/chunk-ZNGFST7K.mjs +0 -348
@@ -1,422 +1 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // packages/terrain/src/index.ts
31
- var src_exports = {};
32
- __export(src_exports, {
33
- TerrainTool: () => TerrainTool
34
- });
35
- module.exports = __toCommonJS(src_exports);
36
-
37
- // packages/terrain/src/TerrainTool.ts
38
- var THREE = __toESM(require("three"));
39
- var TerrainTool = class extends THREE.EventDispatcher {
40
- /**
41
- * Creates a new TerrainTool instance
42
- * @param scene - The Three.js scene to add terrain to
43
- * @param options - Configuration options
44
- */
45
- constructor(scene, options = {}) {
46
- super();
47
- this.mesh = null;
48
- this.currentData = null;
49
- this.isLoading = false;
50
- this.generatedTextureUrls = /* @__PURE__ */ new Set();
51
- this.scene = scene;
52
- this.widthSegments = options.widthSegments ?? 50;
53
- this.depthSegments = options.depthSegments ?? 50;
54
- this.elevationScale = options.elevationScale ?? 1;
55
- this.baseColor = options.baseColor ?? 9139029;
56
- this.wireframe = options.wireframe ?? false;
57
- this.textureUrl = options.textureUrl;
58
- this.mapboxOptions = options.mapbox;
59
- this.receiveShadow = options.receiveShadow ?? true;
60
- this.castShadow = options.castShadow ?? true;
61
- this.useDemoData = options.useDemoData ?? false;
62
- }
63
- /**
64
- * Update Mapbox imagery configuration at runtime
65
- */
66
- setMapboxOptions(options) {
67
- this.mapboxOptions = options;
68
- }
69
- /**
70
- * Loads terrain data and creates a mesh
71
- * @param center - Center coordinates (latitude, longitude)
72
- * @param dimensions - Terrain dimensions in meters
73
- */
74
- async loadTerrain(center, dimensions) {
75
- if (this.isLoading) {
76
- console.warn("Terrain is already loading");
77
- return;
78
- }
79
- this.isLoading = true;
80
- this.dispatchEvent({
81
- type: "updateStarted",
82
- center,
83
- dimensions
84
- });
85
- try {
86
- const terrainData = await this.fetchElevationData(center, dimensions);
87
- this.currentData = terrainData;
88
- this.dispatchEvent({
89
- type: "dataLoaded",
90
- data: terrainData
91
- });
92
- const textureSource = await this.resolveTexture(center, dimensions);
93
- await this.createMesh(terrainData, textureSource);
94
- } catch (error) {
95
- console.error("Error loading terrain:", error);
96
- this.dispatchEvent({
97
- type: "error",
98
- message: "Failed to load terrain",
99
- error
100
- });
101
- } finally {
102
- this.isLoading = false;
103
- }
104
- }
105
- /**
106
- * Updates the terrain with new coordinates and/or dimensions
107
- * @param center - New center coordinates (optional, keeps current if not provided)
108
- * @param dimensions - New dimensions (optional, keeps current if not provided)
109
- */
110
- async updateTerrain(center, dimensions) {
111
- if (!this.currentData && !center) {
112
- console.warn("No current terrain data and no center provided");
113
- return;
114
- }
115
- const newCenter = center || this.currentData.center;
116
- const newDimensions = dimensions || this.currentData.dimensions;
117
- await this.loadTerrain(newCenter, newDimensions);
118
- }
119
- /**
120
- * Fetches elevation data from Open-Elevation API or generates demo data
121
- * @private
122
- */
123
- async fetchElevationData(center, dimensions) {
124
- if (this.useDemoData) {
125
- return this.generateDemoData(center, dimensions);
126
- }
127
- const points = [];
128
- const metersPerDegreeLat = 111320;
129
- const metersPerDegreeLon = 111320 * Math.max(Math.abs(Math.cos(center.latitude * Math.PI / 180)), 1e-6);
130
- const latRange = dimensions.depth / metersPerDegreeLat;
131
- const lonRange = dimensions.width / metersPerDegreeLon;
132
- const latStep = latRange / this.depthSegments;
133
- const lonStep = lonRange / this.widthSegments;
134
- const startLat = center.latitude + latRange / 2;
135
- const startLon = center.longitude - lonRange / 2;
136
- for (let z = 0; z <= this.depthSegments; z++) {
137
- for (let x = 0; x <= this.widthSegments; x++) {
138
- points.push({
139
- latitude: startLat - z * latStep,
140
- longitude: startLon + x * lonStep
141
- });
142
- }
143
- }
144
- const response = await fetch(
145
- "https://api.open-elevation.com/api/v1/lookup",
146
- {
147
- method: "POST",
148
- headers: {
149
- "Content-Type": "application/json"
150
- },
151
- body: JSON.stringify({
152
- locations: points
153
- })
154
- }
155
- );
156
- if (!response.ok) {
157
- throw new Error(`Elevation API error: ${response.statusText}`);
158
- }
159
- const data = await response.json();
160
- const results = data.results;
161
- const elevations = [];
162
- let minElevation = Infinity;
163
- let maxElevation = -Infinity;
164
- for (let z = 0; z <= this.depthSegments; z++) {
165
- const row = [];
166
- for (let x = 0; x <= this.widthSegments; x++) {
167
- const index = z * (this.widthSegments + 1) + x;
168
- const elevation = results[index].elevation;
169
- row.push(elevation);
170
- minElevation = Math.min(minElevation, elevation);
171
- maxElevation = Math.max(maxElevation, elevation);
172
- }
173
- elevations.push(row);
174
- }
175
- return {
176
- center,
177
- dimensions,
178
- elevations,
179
- minElevation,
180
- maxElevation
181
- };
182
- }
183
- /**
184
- * Generates demo terrain data using perlin-like noise
185
- * @private
186
- */
187
- generateDemoData(center, dimensions) {
188
- const elevations = [];
189
- let minElevation = Infinity;
190
- let maxElevation = -Infinity;
191
- const seed = center.latitude + center.longitude;
192
- for (let z = 0; z <= this.depthSegments; z++) {
193
- const row = [];
194
- for (let x = 0; x <= this.widthSegments; x++) {
195
- const nx = x / this.widthSegments * 4;
196
- const nz = z / this.depthSegments * 4;
197
- let elevation = 0;
198
- elevation += Math.sin(nx + seed) * 500;
199
- elevation += Math.cos(nz + seed) * 500;
200
- elevation += Math.sin(nx * 2 + seed) * 200;
201
- elevation += Math.cos(nz * 2 + seed) * 200;
202
- elevation += Math.sin(nx * 4 + seed) * 50;
203
- elevation += Math.cos(nz * 4 + seed) * 50;
204
- elevation += (Math.random() - 0.5) * 30;
205
- row.push(elevation);
206
- minElevation = Math.min(minElevation, elevation);
207
- maxElevation = Math.max(maxElevation, elevation);
208
- }
209
- elevations.push(row);
210
- }
211
- return {
212
- center,
213
- dimensions,
214
- elevations,
215
- minElevation,
216
- maxElevation
217
- };
218
- }
219
- /**
220
- * Creates a terrain mesh from elevation data
221
- * @private
222
- */
223
- async createMesh(data, textureSource) {
224
- if (this.mesh) {
225
- this.scene.remove(this.mesh);
226
- this.mesh.geometry.dispose();
227
- if (Array.isArray(this.mesh.material)) {
228
- this.mesh.material.forEach((mat) => mat.dispose());
229
- } else {
230
- this.mesh.material.dispose();
231
- }
232
- }
233
- const geometry = new THREE.PlaneGeometry(
234
- data.dimensions.width,
235
- data.dimensions.depth,
236
- this.widthSegments,
237
- this.depthSegments
238
- );
239
- const positions = geometry.attributes.position;
240
- let vertexIndex = 0;
241
- for (let z = 0; z <= this.depthSegments; z++) {
242
- for (let x = 0; x <= this.widthSegments; x++) {
243
- const elevation = data.elevations[z][x];
244
- const height = (elevation - data.minElevation) * this.elevationScale;
245
- positions.setZ(vertexIndex, height);
246
- vertexIndex++;
247
- }
248
- }
249
- geometry.computeVertexNormals();
250
- let material;
251
- if (textureSource?.url) {
252
- try {
253
- const texture = await new THREE.TextureLoader().loadAsync(
254
- textureSource.url
255
- );
256
- material = new THREE.MeshStandardMaterial({
257
- map: texture,
258
- wireframe: this.wireframe
259
- });
260
- } catch (error) {
261
- console.warn("Failed to load terrain texture, using base color.", error);
262
- material = new THREE.MeshStandardMaterial({
263
- color: this.baseColor,
264
- wireframe: this.wireframe
265
- });
266
- } finally {
267
- if (textureSource.revokeOnUse) {
268
- this.releaseGeneratedTexture(textureSource.url);
269
- }
270
- }
271
- } else {
272
- material = new THREE.MeshStandardMaterial({
273
- color: this.baseColor,
274
- wireframe: this.wireframe
275
- });
276
- }
277
- this.mesh = new THREE.Mesh(geometry, material);
278
- this.mesh.rotation.x = -Math.PI / 2;
279
- this.mesh.receiveShadow = this.receiveShadow;
280
- this.mesh.castShadow = this.castShadow;
281
- this.scene.add(this.mesh);
282
- this.dispatchEvent({
283
- type: "meshLoaded",
284
- mesh: this.mesh
285
- });
286
- }
287
- async resolveTexture(center, dimensions) {
288
- if (this.textureUrl) {
289
- return {
290
- url: this.textureUrl,
291
- revokeOnUse: false
292
- };
293
- }
294
- if (!this.mapboxOptions) {
295
- return void 0;
296
- }
297
- try {
298
- const url = await this.fetchMapboxTexture(
299
- center,
300
- dimensions,
301
- this.mapboxOptions
302
- );
303
- this.generatedTextureUrls.add(url);
304
- return {
305
- url,
306
- revokeOnUse: true
307
- };
308
- } catch (error) {
309
- console.warn(
310
- "Failed to fetch Mapbox imagery, falling back to base material.",
311
- error
312
- );
313
- return void 0;
314
- }
315
- }
316
- computeBoundingBox(center, dimensions, paddingRatio) {
317
- const metersPerDegreeLat = 111320;
318
- const latRadians = center.latitude * Math.PI / 180;
319
- const cosLat = Math.cos(latRadians);
320
- const metersPerDegreeLon = 111320 * Math.max(Math.abs(cosLat), 1e-6);
321
- const appliedPadding = Math.max(0, paddingRatio);
322
- const widthWithPadding = dimensions.width * (1 + appliedPadding);
323
- const depthWithPadding = dimensions.depth * (1 + appliedPadding);
324
- const halfDepthDegrees = depthWithPadding / 2 / metersPerDegreeLat;
325
- const halfWidthDegrees = widthWithPadding / 2 / metersPerDegreeLon;
326
- const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
327
- const minLat = clamp(center.latitude - halfDepthDegrees, -90, 90);
328
- const maxLat = clamp(center.latitude + halfDepthDegrees, -90, 90);
329
- const minLon = clamp(center.longitude - halfWidthDegrees, -180, 180);
330
- const maxLon = clamp(center.longitude + halfWidthDegrees, -180, 180);
331
- return { minLat, maxLat, minLon, maxLon };
332
- }
333
- async fetchMapboxTexture(center, dimensions, options) {
334
- const styleId = options.styleId ?? "mapbox/satellite-v9";
335
- const normalizedStyleId = styleId.replace("mapbox://styles/", "").replace(/^\/+/, "");
336
- const width = Math.min(
337
- 1280,
338
- Math.max(1, Math.floor(options.imageWidth ?? 1024))
339
- );
340
- const height = Math.min(
341
- 1280,
342
- Math.max(1, Math.floor(options.imageHeight ?? 1024))
343
- );
344
- const highResSuffix = options.highResolution ? "@2x" : "";
345
- const format = options.imageFormat ?? "png";
346
- const paddingRatio = options.paddingRatio ?? 0.1;
347
- const bounds = this.computeBoundingBox(center, dimensions, paddingRatio);
348
- const bbox = `${bounds.minLon.toFixed(6)},${bounds.minLat.toFixed(
349
- 6
350
- )},${bounds.maxLon.toFixed(6)},${bounds.maxLat.toFixed(6)}`;
351
- const params = new URLSearchParams({
352
- access_token: options.accessToken,
353
- format
354
- });
355
- const requestUrl = `https://api.mapbox.com/styles/v1/${normalizedStyleId}/static/[${bbox}]/${width}x${height}${highResSuffix}?${params.toString()}`;
356
- const response = await fetch(requestUrl);
357
- if (!response.ok) {
358
- throw new Error(
359
- `Mapbox imagery request failed: ${response.status} ${response.statusText}`
360
- );
361
- }
362
- const blob = await response.blob();
363
- if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") {
364
- throw new Error(
365
- "URL.createObjectURL is not available in this environment"
366
- );
367
- }
368
- return URL.createObjectURL(blob);
369
- }
370
- releaseGeneratedTexture(url) {
371
- if (!this.generatedTextureUrls.has(url)) {
372
- return;
373
- }
374
- if (typeof URL !== "undefined" && typeof URL.revokeObjectURL === "function") {
375
- URL.revokeObjectURL(url);
376
- }
377
- this.generatedTextureUrls.delete(url);
378
- }
379
- /**
380
- * Gets the current terrain mesh
381
- */
382
- getMesh() {
383
- return this.mesh;
384
- }
385
- /**
386
- * Gets the current terrain data
387
- */
388
- getData() {
389
- return this.currentData;
390
- }
391
- /**
392
- * Checks if terrain is currently loading
393
- */
394
- isTerrainLoading() {
395
- return this.isLoading;
396
- }
397
- /**
398
- * Disposes of all resources
399
- */
400
- dispose() {
401
- if (this.mesh) {
402
- this.scene.remove(this.mesh);
403
- this.mesh.geometry.dispose();
404
- if (Array.isArray(this.mesh.material)) {
405
- this.mesh.material.forEach((mat) => mat.dispose());
406
- } else {
407
- this.mesh.material.dispose();
408
- }
409
- this.mesh = null;
410
- }
411
- this.currentData = null;
412
- if (this.generatedTextureUrls.size > 0) {
413
- for (const url of Array.from(this.generatedTextureUrls)) {
414
- this.releaseGeneratedTexture(url);
415
- }
416
- }
417
- }
418
- };
419
- // Annotate the CommonJS export names for ESM import in node:
420
- 0 && (module.exports = {
421
- TerrainTool
422
- });
1
+ "use strict";var R=Object.create;var S=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var H=(n,d)=>{for(var e in d)S(n,e,{get:d[e],enumerable:!0})},y=(n,d,e,a)=>{if(d&&typeof d=="object"||typeof d=="function")for(let t of P(d))!C.call(n,t)&&t!==e&&S(n,t,{get:()=>d[t],enumerable:!(a=U(d,t))||a.enumerable});return n};var G=(n,d,e)=>(e=n!=null?R(O(n)):{},y(d||!n||!n.__esModule?S(e,"default",{value:n,enumerable:!0}):e,n)),I=n=>y(S({},"__esModule",{value:!0}),n);var $={};H($,{TerrainTool:()=>M});module.exports=I($);var c=G(require("three")),M=class extends c.EventDispatcher{constructor(e,a={}){super();this.mesh=null;this.currentData=null;this.isLoading=!1;this.generatedTextureUrls=new Set;this.scene=e,this.widthSegments=a.widthSegments??50,this.depthSegments=a.depthSegments??50,this.elevationScale=a.elevationScale??1,this.baseColor=a.baseColor??9139029,this.wireframe=a.wireframe??!1,this.textureUrl=a.textureUrl,this.mapboxOptions=a.mapbox,this.receiveShadow=a.receiveShadow??!0,this.castShadow=a.castShadow??!0,this.useDemoData=a.useDemoData??!1}setMapboxOptions(e){this.mapboxOptions=e}async loadTerrain(e,a){if(this.isLoading){console.warn("Terrain is already loading");return}this.isLoading=!0,this.dispatchEvent({type:"updateStarted",center:e,dimensions:a});try{let t=await this.fetchElevationData(e,a);this.currentData=t,this.dispatchEvent({type:"dataLoaded",data:t});let o=await this.resolveTexture(e,a);await this.createMesh(t,o)}catch(t){console.error("Error loading terrain:",t),this.dispatchEvent({type:"error",message:"Failed to load terrain",error:t})}finally{this.isLoading=!1}}async updateTerrain(e,a){if(!this.currentData&&!e){console.warn("No current terrain data and no center provided");return}let t=e||this.currentData.center,o=a||this.currentData.dimensions;await this.loadTerrain(t,o)}async fetchElevationData(e,a){if(this.useDemoData)return this.generateDemoData(e,a);let t=[],o=111320,m=111320*Math.max(Math.abs(Math.cos(e.latitude*Math.PI/180)),1e-6),s=a.depth/o,i=a.width/m,h=s/this.depthSegments,u=i/this.widthSegments,p=e.latitude+s/2,l=e.longitude-i/2;for(let g=0;g<=this.depthSegments;g++)for(let f=0;f<=this.widthSegments;f++)t.push({latitude:p-g*h,longitude:l+f*u});let r=await fetch("https://api.open-elevation.com/api/v1/lookup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({locations:t})});if(!r.ok)throw new Error(`Elevation API error: ${r.statusText}`);let v=(await r.json()).results,x=[],T=1/0,w=-1/0;for(let g=0;g<=this.depthSegments;g++){let f=[];for(let E=0;E<=this.widthSegments;E++){let L=g*(this.widthSegments+1)+E,D=v[L].elevation;f.push(D),T=Math.min(T,D),w=Math.max(w,D)}x.push(f)}return{center:e,dimensions:a,elevations:x,minElevation:T,maxElevation:w}}generateDemoData(e,a){let t=[],o=1/0,m=-1/0,s=e.latitude+e.longitude;for(let i=0;i<=this.depthSegments;i++){let h=[];for(let u=0;u<=this.widthSegments;u++){let p=u/this.widthSegments*4,l=i/this.depthSegments*4,r=0;r+=Math.sin(p+s)*500,r+=Math.cos(l+s)*500,r+=Math.sin(p*2+s)*200,r+=Math.cos(l*2+s)*200,r+=Math.sin(p*4+s)*50,r+=Math.cos(l*4+s)*50,r+=(Math.random()-.5)*30,h.push(r),o=Math.min(o,r),m=Math.max(m,r)}t.push(h)}return{center:e,dimensions:a,elevations:t,minElevation:o,maxElevation:m}}async createMesh(e,a){this.mesh&&(this.scene.remove(this.mesh),this.mesh.geometry.dispose(),Array.isArray(this.mesh.material)?this.mesh.material.forEach(i=>i.dispose()):this.mesh.material.dispose());let t=new c.PlaneGeometry(e.dimensions.width,e.dimensions.depth,this.widthSegments,this.depthSegments),o=t.attributes.position,m=0;for(let i=0;i<=this.depthSegments;i++)for(let h=0;h<=this.widthSegments;h++){let p=(e.elevations[i][h]-e.minElevation)*this.elevationScale;o.setZ(m,p),m++}t.computeVertexNormals();let s;if(a?.url)try{let i=await new c.TextureLoader().loadAsync(a.url);s=new c.MeshStandardMaterial({map:i,wireframe:this.wireframe})}catch(i){console.warn("Failed to load terrain texture, using base color.",i),s=new c.MeshStandardMaterial({color:this.baseColor,wireframe:this.wireframe})}finally{a.revokeOnUse&&this.releaseGeneratedTexture(a.url)}else s=new c.MeshStandardMaterial({color:this.baseColor,wireframe:this.wireframe});this.mesh=new c.Mesh(t,s),this.mesh.rotation.x=-Math.PI/2,this.mesh.receiveShadow=this.receiveShadow,this.mesh.castShadow=this.castShadow,this.scene.add(this.mesh),this.dispatchEvent({type:"meshLoaded",mesh:this.mesh})}async resolveTexture(e,a){if(this.textureUrl)return{url:this.textureUrl,revokeOnUse:!1};if(this.mapboxOptions)try{let t=await this.fetchMapboxTexture(e,a,this.mapboxOptions);return this.generatedTextureUrls.add(t),{url:t,revokeOnUse:!0}}catch(t){console.warn("Failed to fetch Mapbox imagery, falling back to base material.",t);return}}computeBoundingBox(e,a,t){let m=e.latitude*Math.PI/180,s=Math.cos(m),i=111320*Math.max(Math.abs(s),1e-6),h=Math.max(0,t),u=a.width*(1+h),l=a.depth*(1+h)/2/111320,r=u/2/i,b=(g,f,E)=>Math.min(Math.max(g,f),E),v=b(e.latitude-l,-90,90),x=b(e.latitude+l,-90,90),T=b(e.longitude-r,-180,180),w=b(e.longitude+r,-180,180);return{minLat:v,maxLat:x,minLon:T,maxLon:w}}async fetchMapboxTexture(e,a,t){let m=(t.styleId??"mapbox/satellite-v9").replace("mapbox://styles/","").replace(/^\/+/,""),s=Math.min(1280,Math.max(1,Math.floor(t.imageWidth??1024))),i=Math.min(1280,Math.max(1,Math.floor(t.imageHeight??1024))),h=t.highResolution?"@2x":"",u=t.imageFormat??"png",p=t.paddingRatio??.1,l=this.computeBoundingBox(e,a,p),r=`${l.minLon.toFixed(6)},${l.minLat.toFixed(6)},${l.maxLon.toFixed(6)},${l.maxLat.toFixed(6)}`,b=new URLSearchParams({access_token:t.accessToken,format:u}),v=`https://api.mapbox.com/styles/v1/${m}/static/[${r}]/${s}x${i}${h}?${b.toString()}`,x=await fetch(v);if(!x.ok)throw new Error(`Mapbox imagery request failed: ${x.status} ${x.statusText}`);let T=await x.blob();if(typeof URL>"u"||typeof URL.createObjectURL!="function")throw new Error("URL.createObjectURL is not available in this environment");return URL.createObjectURL(T)}releaseGeneratedTexture(e){this.generatedTextureUrls.has(e)&&(typeof URL<"u"&&typeof URL.revokeObjectURL=="function"&&URL.revokeObjectURL(e),this.generatedTextureUrls.delete(e))}getMesh(){return this.mesh}getData(){return this.currentData}isTerrainLoading(){return this.isLoading}dispose(){if(this.mesh&&(this.scene.remove(this.mesh),this.mesh.geometry.dispose(),Array.isArray(this.mesh.material)?this.mesh.material.forEach(e=>e.dispose()):this.mesh.material.dispose(),this.mesh=null),this.currentData=null,this.generatedTextureUrls.size>0)for(let e of Array.from(this.generatedTextureUrls))this.releaseGeneratedTexture(e)}};0&&(module.exports={TerrainTool});
@@ -1,6 +1 @@
1
- import {
2
- TerrainTool
3
- } from "../chunk-FBTT6MU6.mjs";
4
- export {
5
- TerrainTool
6
- };
1
+ import{a}from"../chunk-55YVGK52.mjs";export{a as TerrainTool};