deeptwins-engine-3d 0.1.68 → 0.1.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/drawer/index.d.ts +1 -1
- package/dist/esm/graphicLayer/BaseSource.d.ts +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/map/Map.d.ts +1 -0
- package/dist/esm/map/Map.js +14 -0
- package/dist/umd/deeptwins-engine-3d.min.js +1 -1
- package/package.json +3 -2
- package/dist/esm/sceneFusion/Airway.d.ts +0 -0
- package/dist/esm/sceneFusion/Airway.js +0 -692
|
@@ -1,692 +0,0 @@
|
|
|
1
|
-
// import {
|
|
2
|
-
// centerMean,
|
|
3
|
-
// flattenEach,
|
|
4
|
-
// getCoords,
|
|
5
|
-
// points,
|
|
6
|
-
// type AllGeoJSON,
|
|
7
|
-
// type Feature,
|
|
8
|
-
// type FeatureCollection,
|
|
9
|
-
// type LineString,
|
|
10
|
-
// type Position,
|
|
11
|
-
// } from '@turf/turf';
|
|
12
|
-
// import * as Cesium from 'deeptwins-cesium';
|
|
13
|
-
// import {
|
|
14
|
-
// CanvasTexture,
|
|
15
|
-
// CatmullRomCurve3,
|
|
16
|
-
// DoubleSide,
|
|
17
|
-
// Mesh,
|
|
18
|
-
// MeshBasicMaterial,
|
|
19
|
-
// MeshPhongMaterial,
|
|
20
|
-
// RepeatWrapping,
|
|
21
|
-
// TorusGeometry,
|
|
22
|
-
// TubeGeometry,
|
|
23
|
-
// Vector3,
|
|
24
|
-
// type BufferGeometry,
|
|
25
|
-
// type Group,
|
|
26
|
-
// type Material,
|
|
27
|
-
// type MeshPhongMaterialParameters,
|
|
28
|
-
// type Texture,
|
|
29
|
-
// } from 'three';
|
|
30
|
-
// import { MapContext } from '../map/Map';
|
|
31
|
-
//
|
|
32
|
-
// /** 航道 GeoJSON 坐标:[经度, 纬度, 高度],高度默认 0。 */
|
|
33
|
-
// export type AirwayCoordinate = [number, number, number?];
|
|
34
|
-
//
|
|
35
|
-
// /** 航道中心点或路径点的经纬高描述。 */
|
|
36
|
-
// export type AirwayGeoPosition = {
|
|
37
|
-
// alt?: number;
|
|
38
|
-
// lat: number;
|
|
39
|
-
// lng: number;
|
|
40
|
-
// };
|
|
41
|
-
//
|
|
42
|
-
// type NormalizedAirwayCoordinate = [number, number, number];
|
|
43
|
-
//
|
|
44
|
-
// type NormalizedAirwayGeoPosition = {
|
|
45
|
-
// alt: number;
|
|
46
|
-
// lat: number;
|
|
47
|
-
// lng: number;
|
|
48
|
-
// };
|
|
49
|
-
//
|
|
50
|
-
// /** 航道支持的 GeoJSON 数据。 */
|
|
51
|
-
// export type AirwayGeoJson = AllGeoJSON;
|
|
52
|
-
//
|
|
53
|
-
// /** 航道 LineString Feature 类型别名。 */
|
|
54
|
-
// export type AirwayLineStringFeature = Feature<LineString>;
|
|
55
|
-
//
|
|
56
|
-
// /** 航道 FeatureCollection 类型别名。 */
|
|
57
|
-
// export type AirwayFeatureCollection = FeatureCollection<LineString>;
|
|
58
|
-
//
|
|
59
|
-
// /** 航道程序化流动纹理参数。 */
|
|
60
|
-
// export type AirwayFlowTextureOptions = {
|
|
61
|
-
// height?: number;
|
|
62
|
-
// width?: number;
|
|
63
|
-
// };
|
|
64
|
-
//
|
|
65
|
-
// /** SceneFusion 等离子管线效果参数。 */
|
|
66
|
-
// export type AirwayPlasmaOptions = {
|
|
67
|
-
// /** 纹理和噪声沿管线轴向的密度。 */
|
|
68
|
-
// density?: number;
|
|
69
|
-
// /** 边缘 Fresnel 辉光强度曲线。 */
|
|
70
|
-
// fresnelPower?: number;
|
|
71
|
-
// /** 最终发光颜色强度。 */
|
|
72
|
-
// intensity?: number;
|
|
73
|
-
// /** 流动动画速度。 */
|
|
74
|
-
// speed?: number;
|
|
75
|
-
// };
|
|
76
|
-
//
|
|
77
|
-
// /** 航道外部辅助光圈参数。 */
|
|
78
|
-
// export type AirwayHaloOptions = {
|
|
79
|
-
// /** 是否绘制沿路径流动的光圈。 */
|
|
80
|
-
// enabled?: boolean;
|
|
81
|
-
// /** 光圈数量。 */
|
|
82
|
-
// count?: number;
|
|
83
|
-
// /** 光圈颜色。 */
|
|
84
|
-
// color?: MeshPhongMaterialParameters['color'];
|
|
85
|
-
// /** 基础透明度。 */
|
|
86
|
-
// opacity?: number;
|
|
87
|
-
// /** 透明度脉冲幅度。 */
|
|
88
|
-
// opacityAmplitude?: number;
|
|
89
|
-
// /** 透明度脉冲速度。 */
|
|
90
|
-
// opacitySpeed?: number;
|
|
91
|
-
// /** 光圈相对主航道半径的外扩距离。 */
|
|
92
|
-
// radiusOffset?: number;
|
|
93
|
-
// /** 缩放脉冲基础值。 */
|
|
94
|
-
// scaleBase?: number;
|
|
95
|
-
// /** 缩放脉冲幅度。 */
|
|
96
|
-
// scaleAmplitude?: number;
|
|
97
|
-
// /** 缩放脉冲速度。 */
|
|
98
|
-
// scaleSpeed?: number;
|
|
99
|
-
// /** 光圈沿路径前进速度。 */
|
|
100
|
-
// speed?: number;
|
|
101
|
-
// /** 光圈截面分段。 */
|
|
102
|
-
// radialSegments?: number;
|
|
103
|
-
// /** 光圈管径。 */
|
|
104
|
-
// tubeRadius?: number;
|
|
105
|
-
// /** 光圈环向分段。 */
|
|
106
|
-
// tubularSegments?: number;
|
|
107
|
-
// };
|
|
108
|
-
//
|
|
109
|
-
// /** 航道绘制参数。 */
|
|
110
|
-
// export type AirwayOptions = {
|
|
111
|
-
// /** 自定义航道锚点;默认使用路径坐标平均中心。 */
|
|
112
|
-
// center?: AirwayGeoPosition;
|
|
113
|
-
// /** 是否闭合路径。 */
|
|
114
|
-
// closed?: boolean;
|
|
115
|
-
// /** 直接传入航道坐标;优先级高于 geoJson。 */
|
|
116
|
-
// coordinates?: AirwayCoordinate[];
|
|
117
|
-
// /** CatmullRom 曲线张力。 */
|
|
118
|
-
// curveTension?: number;
|
|
119
|
-
// /** 从 GeoJSON 中读取第一条 LineString,支持 Feature / FeatureCollection / Geometry。 */
|
|
120
|
-
// geoJson?: AirwayGeoJson;
|
|
121
|
-
// /** 外部辅助光圈参数。 */
|
|
122
|
-
// halo?: AirwayHaloOptions;
|
|
123
|
-
// /** Three MeshPhongMaterial 参数。 */
|
|
124
|
-
// material?: MeshPhongMaterialParameters;
|
|
125
|
-
// /** SceneFusion 等离子管线效果参数。 */
|
|
126
|
-
// plasma?: AirwayPlasmaOptions;
|
|
127
|
-
// /** 主航道半径,单位米。 */
|
|
128
|
-
// radius?: number;
|
|
129
|
-
// /** 主航道径向分段。 */
|
|
130
|
-
// radialSegments?: number;
|
|
131
|
-
// /** 程序化流动纹理参数。 */
|
|
132
|
-
// flowTexture?: AirwayFlowTextureOptions;
|
|
133
|
-
// /** 主航道轴向分段。 */
|
|
134
|
-
// tubularSegments?: number;
|
|
135
|
-
// };
|
|
136
|
-
//
|
|
137
|
-
// type ResolvedAirwayOptions = {
|
|
138
|
-
// center?: AirwayGeoPosition;
|
|
139
|
-
// closed: boolean;
|
|
140
|
-
// coordinates?: AirwayCoordinate[];
|
|
141
|
-
// curveTension: number;
|
|
142
|
-
// flowTexture: Required<AirwayFlowTextureOptions>;
|
|
143
|
-
// geoJson?: AirwayGeoJson;
|
|
144
|
-
// halo: Required<AirwayHaloOptions>;
|
|
145
|
-
// material: MeshPhongMaterialParameters;
|
|
146
|
-
// plasma: Required<AirwayPlasmaOptions>;
|
|
147
|
-
// radialSegments: number;
|
|
148
|
-
// radius: number;
|
|
149
|
-
// tubularSegments: number;
|
|
150
|
-
// };
|
|
151
|
-
//
|
|
152
|
-
// /** 主航道默认几何参数。 */
|
|
153
|
-
// export const AIRWAY_DEFAULT_OPTIONS = {
|
|
154
|
-
// closed: false,
|
|
155
|
-
// curveTension: 0.12,
|
|
156
|
-
// radialSegments: 36,
|
|
157
|
-
// radius: 50,
|
|
158
|
-
// tubularSegments: 320,
|
|
159
|
-
// } as const;
|
|
160
|
-
//
|
|
161
|
-
// /** 航道默认材质参数。 */
|
|
162
|
-
// export const AIRWAY_DEFAULT_MATERIAL_OPTIONS = {
|
|
163
|
-
// color: '#1d4ed8',
|
|
164
|
-
// emissive: '#38bdf8',
|
|
165
|
-
// emissiveIntensity: 1.15,
|
|
166
|
-
// opacity: 0.58,
|
|
167
|
-
// shininess: 140,
|
|
168
|
-
// side: DoubleSide,
|
|
169
|
-
// specular: '#e0f2fe',
|
|
170
|
-
// transparent: true,
|
|
171
|
-
// } as const;
|
|
172
|
-
//
|
|
173
|
-
// /** 航道默认等离子效果参数。 */
|
|
174
|
-
// export const AIRWAY_DEFAULT_PLASMA_OPTIONS = {
|
|
175
|
-
// density: 2.2,
|
|
176
|
-
// fresnelPower: 2.4,
|
|
177
|
-
// intensity: 1.62,
|
|
178
|
-
// speed: 3,
|
|
179
|
-
// } as const;
|
|
180
|
-
//
|
|
181
|
-
// /** 航道默认辅助光圈参数。 */
|
|
182
|
-
// export const AIRWAY_DEFAULT_HALO_OPTIONS = {
|
|
183
|
-
// count: 7,
|
|
184
|
-
// color: '#93c5fd',
|
|
185
|
-
// enabled: true,
|
|
186
|
-
// opacity: 0.22,
|
|
187
|
-
// opacityAmplitude: 0.1,
|
|
188
|
-
// opacitySpeed: 5,
|
|
189
|
-
// radialSegments: 18,
|
|
190
|
-
// radiusOffset: 5.5,
|
|
191
|
-
// scaleAmplitude: 0.16,
|
|
192
|
-
// scaleBase: 0.92,
|
|
193
|
-
// scaleSpeed: 6,
|
|
194
|
-
// speed: 0.065,
|
|
195
|
-
// tubeRadius: 1.2,
|
|
196
|
-
// tubularSegments: 48,
|
|
197
|
-
// } as const;
|
|
198
|
-
//
|
|
199
|
-
// /** 航道默认程序化纹理参数。 */
|
|
200
|
-
// export const AIRWAY_DEFAULT_FLOW_TEXTURE_OPTIONS = {
|
|
201
|
-
// height: 256,
|
|
202
|
-
// width: 1024,
|
|
203
|
-
// } as const;
|
|
204
|
-
//
|
|
205
|
-
// /**
|
|
206
|
-
// * 飞行航道封装。
|
|
207
|
-
// *
|
|
208
|
-
// * 负责把 GeoJSON LineString / 坐标数组转换成 SceneFusion 可渲染的 Three Tube,
|
|
209
|
-
// * 并内置程序化等离子材质与沿线流动光圈,调用侧只需要传入地图和路径数据。
|
|
210
|
-
// */
|
|
211
|
-
// class Airway {
|
|
212
|
-
// /** 地图上下文。 */
|
|
213
|
-
// public _mapContext: MapContext | undefined;
|
|
214
|
-
// public center: NormalizedAirwayGeoPosition | undefined;
|
|
215
|
-
// public coordinates: NormalizedAirwayCoordinate[] | undefined;
|
|
216
|
-
// public primitive: any;
|
|
217
|
-
//
|
|
218
|
-
// private fusion: any;
|
|
219
|
-
// private ownedFlowTexture: Texture | undefined;
|
|
220
|
-
// private ownsFusionLoop = false;
|
|
221
|
-
// private readonly baseOptions: AirwayOptions;
|
|
222
|
-
// private root: Group | undefined;
|
|
223
|
-
// private stopVisualEffects: () => void = () => {};
|
|
224
|
-
//
|
|
225
|
-
// constructor(map: any, options: AirwayOptions = {}) {
|
|
226
|
-
// this._mapContext = map._mapContext;
|
|
227
|
-
// this.baseOptions = options;
|
|
228
|
-
//
|
|
229
|
-
// if (this.hasRenderableSource(options)) {
|
|
230
|
-
// this.draw();
|
|
231
|
-
// }
|
|
232
|
-
// }
|
|
233
|
-
//
|
|
234
|
-
// /** 获取 Cesium Viewer 实例。 */
|
|
235
|
-
// public getMap(): Cesium.Viewer | undefined {
|
|
236
|
-
// return this._mapContext && this._mapContext.getMap();
|
|
237
|
-
// }
|
|
238
|
-
//
|
|
239
|
-
// /**
|
|
240
|
-
// * 绘制航道。
|
|
241
|
-
// * @param options 本次绘制参数,会覆盖构造函数中的同名参数。
|
|
242
|
-
// */
|
|
243
|
-
// public draw(options: AirwayOptions = {}) {
|
|
244
|
-
// const map = this.getMap() as any;
|
|
245
|
-
//
|
|
246
|
-
// if (!map) {
|
|
247
|
-
// throw new Error('地图实例不存在,无法绘制航道。');
|
|
248
|
-
// }
|
|
249
|
-
//
|
|
250
|
-
// const resolvedOptions = this.resolveOptions(options);
|
|
251
|
-
// const coordinates = this.resolveCoordinates(resolvedOptions);
|
|
252
|
-
// const center = this.normalizeGeoPosition(
|
|
253
|
-
// resolvedOptions.center ?? this.getCenter(coordinates),
|
|
254
|
-
// );
|
|
255
|
-
// const flowTexture =
|
|
256
|
-
// resolvedOptions.material.map ??
|
|
257
|
-
// this.createFlowTexture(resolvedOptions.flowTexture);
|
|
258
|
-
//
|
|
259
|
-
// if (!resolvedOptions.material.map) {
|
|
260
|
-
// this.ownedFlowTexture = flowTexture;
|
|
261
|
-
// }
|
|
262
|
-
//
|
|
263
|
-
// this.fusion = new SceneFusion(map);
|
|
264
|
-
// this.startFusionLoop(this.fusion);
|
|
265
|
-
//
|
|
266
|
-
// const primitive = this.fusion.createPrimitive({
|
|
267
|
-
// center,
|
|
268
|
-
// createRoot: ({ group, convertToThreePosition }) => {
|
|
269
|
-
// const pathPoints = coordinates.map((coordinate) => {
|
|
270
|
-
// const position = convertToThreePosition(
|
|
271
|
-
// this.toGeoPosition(coordinate),
|
|
272
|
-
// );
|
|
273
|
-
// return new Vector3(position.x, position.y, position.z);
|
|
274
|
-
// });
|
|
275
|
-
// const curve = new CatmullRomCurve3(
|
|
276
|
-
// pathPoints,
|
|
277
|
-
// resolvedOptions.closed,
|
|
278
|
-
// 'catmullrom',
|
|
279
|
-
// resolvedOptions.curveTension,
|
|
280
|
-
// );
|
|
281
|
-
// const material = SceneFusion.applyPlasmaTubeEffect(
|
|
282
|
-
// new MeshPhongMaterial({
|
|
283
|
-
// ...resolvedOptions.material,
|
|
284
|
-
// map: flowTexture,
|
|
285
|
-
// }),
|
|
286
|
-
// resolvedOptions.plasma,
|
|
287
|
-
// );
|
|
288
|
-
// const channelTube = new Mesh(
|
|
289
|
-
// new TubeGeometry(
|
|
290
|
-
// curve,
|
|
291
|
-
// resolvedOptions.tubularSegments,
|
|
292
|
-
// resolvedOptions.radius,
|
|
293
|
-
// resolvedOptions.radialSegments,
|
|
294
|
-
// resolvedOptions.closed,
|
|
295
|
-
// ),
|
|
296
|
-
// material,
|
|
297
|
-
// );
|
|
298
|
-
//
|
|
299
|
-
// group.add(channelTube);
|
|
300
|
-
// this.root = group;
|
|
301
|
-
//
|
|
302
|
-
// if (resolvedOptions.halo.enabled) {
|
|
303
|
-
// const haloEffects = this.createHaloRingEffects(
|
|
304
|
-
// curve,
|
|
305
|
-
// resolvedOptions.radius,
|
|
306
|
-
// resolvedOptions.halo,
|
|
307
|
-
// );
|
|
308
|
-
//
|
|
309
|
-
// haloEffects.haloRings.forEach((mesh) => {
|
|
310
|
-
// group.add(mesh);
|
|
311
|
-
// });
|
|
312
|
-
//
|
|
313
|
-
// this.stopVisualEffects = haloEffects.start();
|
|
314
|
-
// }
|
|
315
|
-
//
|
|
316
|
-
// return group;
|
|
317
|
-
// },
|
|
318
|
-
// });
|
|
319
|
-
//
|
|
320
|
-
// if (!primitive) {
|
|
321
|
-
// throw new Error('航道 Primitive 创建失败。');
|
|
322
|
-
// }
|
|
323
|
-
//
|
|
324
|
-
// this.center = center;
|
|
325
|
-
// this.coordinates = coordinates;
|
|
326
|
-
// this.primitive = primitive;
|
|
327
|
-
// }
|
|
328
|
-
//
|
|
329
|
-
// /** 销毁航道实例。 */
|
|
330
|
-
// public destroy() {
|
|
331
|
-
// this.stopVisualEffects();
|
|
332
|
-
// this.stopVisualEffects = () => {};
|
|
333
|
-
// this.releaseFusion();
|
|
334
|
-
// this.disposeRoot();
|
|
335
|
-
// this.ownedFlowTexture?.dispose();
|
|
336
|
-
// this.ownedFlowTexture = undefined;
|
|
337
|
-
// this.fusion?.removePrimitive(this.primitive);
|
|
338
|
-
// this.center = undefined;
|
|
339
|
-
// this.coordinates = undefined;
|
|
340
|
-
// this.primitive = undefined;
|
|
341
|
-
// }
|
|
342
|
-
//
|
|
343
|
-
// private resolveOptions(options: AirwayOptions): ResolvedAirwayOptions {
|
|
344
|
-
// return {
|
|
345
|
-
// ...AIRWAY_DEFAULT_OPTIONS,
|
|
346
|
-
// ...this.baseOptions,
|
|
347
|
-
// ...options,
|
|
348
|
-
// flowTexture: {
|
|
349
|
-
// ...AIRWAY_DEFAULT_FLOW_TEXTURE_OPTIONS,
|
|
350
|
-
// ...this.baseOptions.flowTexture,
|
|
351
|
-
// ...options.flowTexture,
|
|
352
|
-
// },
|
|
353
|
-
// halo: {
|
|
354
|
-
// ...AIRWAY_DEFAULT_HALO_OPTIONS,
|
|
355
|
-
// ...this.baseOptions.halo,
|
|
356
|
-
// ...options.halo,
|
|
357
|
-
// },
|
|
358
|
-
// material: {
|
|
359
|
-
// ...AIRWAY_DEFAULT_MATERIAL_OPTIONS,
|
|
360
|
-
// ...this.baseOptions.material,
|
|
361
|
-
// ...options.material,
|
|
362
|
-
// },
|
|
363
|
-
// plasma: {
|
|
364
|
-
// ...AIRWAY_DEFAULT_PLASMA_OPTIONS,
|
|
365
|
-
// ...this.baseOptions.plasma,
|
|
366
|
-
// ...options.plasma,
|
|
367
|
-
// },
|
|
368
|
-
// };
|
|
369
|
-
// }
|
|
370
|
-
//
|
|
371
|
-
// private resolveCoordinates(
|
|
372
|
-
// options: Pick<AirwayOptions, 'coordinates' | 'geoJson'>,
|
|
373
|
-
// ) {
|
|
374
|
-
// if (options.coordinates) {
|
|
375
|
-
// return this.normalizeCoordinates(options.coordinates);
|
|
376
|
-
// }
|
|
377
|
-
//
|
|
378
|
-
// if (options.geoJson) {
|
|
379
|
-
// return this.getCoordinatesFromGeoJson(options.geoJson);
|
|
380
|
-
// }
|
|
381
|
-
//
|
|
382
|
-
// throw new Error('绘制航道需要传入 coordinates 或 geoJson。');
|
|
383
|
-
// }
|
|
384
|
-
//
|
|
385
|
-
// private normalizeGeoPosition(
|
|
386
|
-
// position: AirwayGeoPosition,
|
|
387
|
-
// ): NormalizedAirwayGeoPosition {
|
|
388
|
-
// return {
|
|
389
|
-
// alt: position.alt ?? 0,
|
|
390
|
-
// lat: position.lat,
|
|
391
|
-
// lng: position.lng,
|
|
392
|
-
// };
|
|
393
|
-
// }
|
|
394
|
-
//
|
|
395
|
-
// private getCoordinatesFromGeoJson(
|
|
396
|
-
// geoJson: AirwayGeoJson,
|
|
397
|
-
// ): NormalizedAirwayCoordinate[] {
|
|
398
|
-
// let lineCoordinates: Position[] | undefined;
|
|
399
|
-
//
|
|
400
|
-
// flattenEach(geoJson, (feature) => {
|
|
401
|
-
// if (lineCoordinates || feature.geometry?.type !== 'LineString') {
|
|
402
|
-
// return;
|
|
403
|
-
// }
|
|
404
|
-
//
|
|
405
|
-
// lineCoordinates = (feature as Feature<LineString>).geometry.coordinates;
|
|
406
|
-
// });
|
|
407
|
-
//
|
|
408
|
-
// if (!lineCoordinates) {
|
|
409
|
-
// throw new Error('geoJson 需要至少一条 LineString 作为航道路径。');
|
|
410
|
-
// }
|
|
411
|
-
//
|
|
412
|
-
// return this.normalizeCoordinates(lineCoordinates);
|
|
413
|
-
// }
|
|
414
|
-
//
|
|
415
|
-
// private normalizeCoordinates(
|
|
416
|
-
// coordinates: ReadonlyArray<AirwayCoordinate | Position>,
|
|
417
|
-
// ): NormalizedAirwayCoordinate[] {
|
|
418
|
-
// if (!Array.isArray(coordinates) || coordinates.length < 2) {
|
|
419
|
-
// throw new Error('航道路径至少需要两个坐标点。');
|
|
420
|
-
// }
|
|
421
|
-
//
|
|
422
|
-
// return coordinates.map((coordinate) => {
|
|
423
|
-
// const [longitude, latitude, altitude = 0] = coordinate;
|
|
424
|
-
//
|
|
425
|
-
// if (
|
|
426
|
-
// !Number.isFinite(longitude) ||
|
|
427
|
-
// !Number.isFinite(latitude) ||
|
|
428
|
-
// !Number.isFinite(altitude)
|
|
429
|
-
// ) {
|
|
430
|
-
// throw new Error('航道坐标必须是有效的经纬高数字。');
|
|
431
|
-
// }
|
|
432
|
-
//
|
|
433
|
-
// return [longitude, latitude, altitude];
|
|
434
|
-
// });
|
|
435
|
-
// }
|
|
436
|
-
//
|
|
437
|
-
// private hasRenderableSource(options: AirwayOptions) {
|
|
438
|
-
// return (
|
|
439
|
-
// (Array.isArray(options.coordinates) && options.coordinates.length > 1) ||
|
|
440
|
-
// !!options.geoJson
|
|
441
|
-
// );
|
|
442
|
-
// }
|
|
443
|
-
//
|
|
444
|
-
// private createHaloRingEffects(
|
|
445
|
-
// curve: CatmullRomCurve3,
|
|
446
|
-
// channelRadius: number,
|
|
447
|
-
// options: Required<AirwayHaloOptions>,
|
|
448
|
-
// ) {
|
|
449
|
-
// const haloRingGeometry = new TorusGeometry(
|
|
450
|
-
// channelRadius + options.radiusOffset,
|
|
451
|
-
// options.tubeRadius,
|
|
452
|
-
// options.radialSegments,
|
|
453
|
-
// options.tubularSegments,
|
|
454
|
-
// );
|
|
455
|
-
// const zAxis = new Vector3(0, 0, 1);
|
|
456
|
-
// const haloRings: Mesh[] = [];
|
|
457
|
-
//
|
|
458
|
-
// for (let index = 0; index < options.count; index += 1) {
|
|
459
|
-
// const haloRing = new Mesh(
|
|
460
|
-
// haloRingGeometry,
|
|
461
|
-
// new MeshBasicMaterial({
|
|
462
|
-
// color: options.color,
|
|
463
|
-
// opacity: options.opacity,
|
|
464
|
-
// transparent: true,
|
|
465
|
-
// }),
|
|
466
|
-
// );
|
|
467
|
-
// haloRing.userData.offset = index / options.count;
|
|
468
|
-
// haloRings.push(haloRing);
|
|
469
|
-
// }
|
|
470
|
-
//
|
|
471
|
-
// const start = () => {
|
|
472
|
-
// let animationFrameId = 0;
|
|
473
|
-
// let disposed = false;
|
|
474
|
-
//
|
|
475
|
-
// const tick = (time: number) => {
|
|
476
|
-
// if (disposed) {
|
|
477
|
-
// return;
|
|
478
|
-
// }
|
|
479
|
-
//
|
|
480
|
-
// const seconds = time * 0.001;
|
|
481
|
-
//
|
|
482
|
-
// haloRings.forEach((mesh, index) => {
|
|
483
|
-
// const progress = (seconds * options.speed + mesh.userData.offset) % 1;
|
|
484
|
-
// const point = curve.getPointAt(progress);
|
|
485
|
-
// const tangent = curve.getTangentAt(progress).normalize();
|
|
486
|
-
// const pulse =
|
|
487
|
-
// options.scaleBase +
|
|
488
|
-
// Math.sin(seconds * options.scaleSpeed + index * 0.9) *
|
|
489
|
-
// options.scaleAmplitude;
|
|
490
|
-
// const opacity =
|
|
491
|
-
// options.opacity +
|
|
492
|
-
// Math.sin(seconds * options.opacitySpeed + index * 0.75) *
|
|
493
|
-
// options.opacityAmplitude;
|
|
494
|
-
// const material = mesh.material as MeshBasicMaterial;
|
|
495
|
-
//
|
|
496
|
-
// mesh.position.copy(point);
|
|
497
|
-
// mesh.quaternion.setFromUnitVectors(zAxis, tangent);
|
|
498
|
-
// mesh.scale.setScalar(pulse);
|
|
499
|
-
// material.opacity = Math.max(0, Math.min(1, opacity));
|
|
500
|
-
// });
|
|
501
|
-
//
|
|
502
|
-
// animationFrameId = window.requestAnimationFrame(tick);
|
|
503
|
-
// };
|
|
504
|
-
//
|
|
505
|
-
// animationFrameId = window.requestAnimationFrame(tick);
|
|
506
|
-
//
|
|
507
|
-
// return () => {
|
|
508
|
-
// disposed = true;
|
|
509
|
-
// window.cancelAnimationFrame(animationFrameId);
|
|
510
|
-
// };
|
|
511
|
-
// };
|
|
512
|
-
//
|
|
513
|
-
// return {
|
|
514
|
-
// haloRings,
|
|
515
|
-
// start,
|
|
516
|
-
// };
|
|
517
|
-
// }
|
|
518
|
-
//
|
|
519
|
-
// private startFusionLoop(fusion: SceneFusion) {
|
|
520
|
-
// const map = this.getMap() as any;
|
|
521
|
-
//
|
|
522
|
-
// if (typeof map?.addSceneFusion === 'function') {
|
|
523
|
-
// map.addSceneFusion(fusion);
|
|
524
|
-
// this.ownsFusionLoop = true;
|
|
525
|
-
// }
|
|
526
|
-
// }
|
|
527
|
-
//
|
|
528
|
-
// private releaseFusion() {
|
|
529
|
-
// if (!this.fusion) {
|
|
530
|
-
// return;
|
|
531
|
-
// }
|
|
532
|
-
//
|
|
533
|
-
// const map = this.getMap() as any;
|
|
534
|
-
//
|
|
535
|
-
// if (
|
|
536
|
-
// this.ownsFusionLoop &&
|
|
537
|
-
// map?._fusion === this.fusion &&
|
|
538
|
-
// typeof map.removeSceneFusion === 'function'
|
|
539
|
-
// ) {
|
|
540
|
-
// map.removeSceneFusion();
|
|
541
|
-
// } else {
|
|
542
|
-
// this.fusion.destroy();
|
|
543
|
-
// }
|
|
544
|
-
//
|
|
545
|
-
// this.fusion = undefined;
|
|
546
|
-
// this.ownsFusionLoop = false;
|
|
547
|
-
// }
|
|
548
|
-
//
|
|
549
|
-
// private disposeRoot() {
|
|
550
|
-
// if (!this.root) {
|
|
551
|
-
// return;
|
|
552
|
-
// }
|
|
553
|
-
//
|
|
554
|
-
// const geometries = new Set<BufferGeometry>();
|
|
555
|
-
// const materials = new Set<Material>();
|
|
556
|
-
//
|
|
557
|
-
// this.root.traverse((node) => {
|
|
558
|
-
// if (!(node instanceof Mesh)) {
|
|
559
|
-
// return;
|
|
560
|
-
// }
|
|
561
|
-
//
|
|
562
|
-
// geometries.add(node.geometry);
|
|
563
|
-
//
|
|
564
|
-
// if (Array.isArray(node.material)) {
|
|
565
|
-
// node.material.forEach((material) => materials.add(material));
|
|
566
|
-
// } else {
|
|
567
|
-
// materials.add(node.material);
|
|
568
|
-
// }
|
|
569
|
-
// });
|
|
570
|
-
//
|
|
571
|
-
// geometries.forEach((geometry) => geometry.dispose());
|
|
572
|
-
// materials.forEach((material) => material.dispose());
|
|
573
|
-
// this.root.clear();
|
|
574
|
-
// this.root = undefined;
|
|
575
|
-
// }
|
|
576
|
-
//
|
|
577
|
-
// /** 把 GeoJSON 坐标转换为经纬高对象。 */
|
|
578
|
-
// private toGeoPosition(
|
|
579
|
-
// coordinate: AirwayCoordinate,
|
|
580
|
-
// ): NormalizedAirwayGeoPosition {
|
|
581
|
-
// const [longitude, latitude, altitude = 0] = coordinate;
|
|
582
|
-
//
|
|
583
|
-
// return {
|
|
584
|
-
// alt: altitude,
|
|
585
|
-
// lat: latitude,
|
|
586
|
-
// lng: longitude,
|
|
587
|
-
// };
|
|
588
|
-
// }
|
|
589
|
-
//
|
|
590
|
-
// /**
|
|
591
|
-
// * 计算航道坐标中心。
|
|
592
|
-
// * @param coordinates 航道路径坐标。
|
|
593
|
-
// */
|
|
594
|
-
// private getCenter(
|
|
595
|
-
// coordinates: AirwayCoordinate[],
|
|
596
|
-
// ): NormalizedAirwayGeoPosition {
|
|
597
|
-
// const normalizedCoordinates = this.normalizeCoordinates(coordinates);
|
|
598
|
-
// const centerPoint = centerMean(
|
|
599
|
-
// points(
|
|
600
|
-
// normalizedCoordinates.map(([longitude, latitude]) => [
|
|
601
|
-
// longitude,
|
|
602
|
-
// latitude,
|
|
603
|
-
// ]),
|
|
604
|
-
// ),
|
|
605
|
-
// );
|
|
606
|
-
// const [longitude, latitude] = getCoords(centerPoint) as Position;
|
|
607
|
-
// const altitude =
|
|
608
|
-
// normalizedCoordinates.reduce(
|
|
609
|
-
// (accumulator, [, , currentAltitude]) => accumulator + currentAltitude,
|
|
610
|
-
// 0,
|
|
611
|
-
// ) / normalizedCoordinates.length;
|
|
612
|
-
//
|
|
613
|
-
// return {
|
|
614
|
-
// alt: altitude,
|
|
615
|
-
// lat: latitude,
|
|
616
|
-
// lng: longitude,
|
|
617
|
-
// };
|
|
618
|
-
// }
|
|
619
|
-
//
|
|
620
|
-
// /**
|
|
621
|
-
// * 创建航道内置流动纹理。
|
|
622
|
-
// * @param options 纹理尺寸参数。
|
|
623
|
-
// */
|
|
624
|
-
// private createFlowTexture(
|
|
625
|
-
// options: AirwayFlowTextureOptions = {},
|
|
626
|
-
// ): CanvasTexture {
|
|
627
|
-
// const width = options.width ?? AIRWAY_DEFAULT_FLOW_TEXTURE_OPTIONS.width;
|
|
628
|
-
// const height = options.height ?? AIRWAY_DEFAULT_FLOW_TEXTURE_OPTIONS.height;
|
|
629
|
-
// const canvas = document.createElement('canvas');
|
|
630
|
-
//
|
|
631
|
-
// canvas.width = width;
|
|
632
|
-
// canvas.height = height;
|
|
633
|
-
//
|
|
634
|
-
// const context = canvas.getContext('2d');
|
|
635
|
-
//
|
|
636
|
-
// if (!context) {
|
|
637
|
-
// throw new Error('无法创建航道流动纹理。');
|
|
638
|
-
// }
|
|
639
|
-
//
|
|
640
|
-
// const imageData = context.createImageData(width, height);
|
|
641
|
-
// const tau = Math.PI * 2;
|
|
642
|
-
//
|
|
643
|
-
// for (let pixelY = 0; pixelY < height; pixelY += 1) {
|
|
644
|
-
// for (let pixelX = 0; pixelX < width; pixelX += 1) {
|
|
645
|
-
// const horizontalRatio = pixelX / width;
|
|
646
|
-
// const verticalRatio = pixelY / height;
|
|
647
|
-
// const flowRatio = horizontalRatio * 0.29;
|
|
648
|
-
// const centeredVertical = (verticalRatio - 0.5) * 2;
|
|
649
|
-
// const band = Math.exp(-centeredVertical * centeredVertical * 5.8);
|
|
650
|
-
// const waveA = Math.sin(flowRatio * tau * 1.0);
|
|
651
|
-
// const waveB = Math.sin(
|
|
652
|
-
// flowRatio * tau * 2.2 + verticalRatio * tau * 1.3,
|
|
653
|
-
// );
|
|
654
|
-
// const waveC = Math.sin(
|
|
655
|
-
// flowRatio * tau * 4.6 - verticalRatio * tau * 2.8,
|
|
656
|
-
// );
|
|
657
|
-
// const energy = 0.48 + waveA * 0.22 + waveB * 0.16 + waveC * 0.08;
|
|
658
|
-
// const filament = Math.max(
|
|
659
|
-
// 0,
|
|
660
|
-
// Math.sin(
|
|
661
|
-
// flowRatio * tau * 3.6 + Math.sin(verticalRatio * tau * 2.0) * 0.45,
|
|
662
|
-
// ),
|
|
663
|
-
// );
|
|
664
|
-
// const glow = Math.min(
|
|
665
|
-
// 1,
|
|
666
|
-
// band * (0.42 + energy * 0.5) + filament ** 7 * 0.9,
|
|
667
|
-
// );
|
|
668
|
-
// const red = Math.round(18 + glow * 70);
|
|
669
|
-
// const green = Math.round(110 + glow * 145);
|
|
670
|
-
// const blue = Math.round(210 + glow * 45);
|
|
671
|
-
// const alpha = Math.round(
|
|
672
|
-
// Math.min(1, band * 0.78 + filament ** 5 * 0.62) * 255,
|
|
673
|
-
// );
|
|
674
|
-
// const dataIndex = (pixelY * width + pixelX) * 4;
|
|
675
|
-
//
|
|
676
|
-
// imageData.data[dataIndex] = Math.min(255, red);
|
|
677
|
-
// imageData.data[dataIndex + 1] = Math.min(255, green);
|
|
678
|
-
// imageData.data[dataIndex + 2] = Math.min(255, blue);
|
|
679
|
-
// imageData.data[dataIndex + 3] = alpha;
|
|
680
|
-
// }
|
|
681
|
-
// }
|
|
682
|
-
//
|
|
683
|
-
// context.putImageData(imageData, 0, 0);
|
|
684
|
-
//
|
|
685
|
-
// const texture = new CanvasTexture(canvas);
|
|
686
|
-
// texture.wrapS = RepeatWrapping;
|
|
687
|
-
// texture.wrapT = RepeatWrapping;
|
|
688
|
-
// return texture;
|
|
689
|
-
// }
|
|
690
|
-
// }
|
|
691
|
-
//
|
|
692
|
-
// export default Airway;
|