@hzab/map-combine 0.4.2-alpha.1 → 0.4.2-alpha.12

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/CHANGELOG.md +8 -0
  2. package/package.json +5 -5
  3. package/src/amap/AMap.ts +318 -306
  4. package/src/amap/AMapEvent.ts +110 -54
  5. package/src/amap/AMapLayer.ts +241 -0
  6. package/src/amap/AMapPoint.ts +140 -143
  7. package/src/amap/AMapPolygon.ts +214 -195
  8. package/src/amap/AMapPolyline.ts +199 -185
  9. package/src/basic/BasicBusiness.ts +5 -5
  10. package/src/basic/BasicModel.ts +49 -0
  11. package/src/basic/Layer.ts +154 -0
  12. package/src/basic/MapCombine.ts +105 -98
  13. package/src/basic/MapElement.ts +2 -1
  14. package/src/basic/MapEvent.ts +5 -0
  15. package/src/basic/Point.ts +1 -0
  16. package/src/basic/PointAggregation.tsx +22 -11
  17. package/src/basic/ReactPopup.tsx +3 -0
  18. package/src/basic/Tile3D.ts +0 -1
  19. package/src/cesium/CesiumEvent.ts +97 -84
  20. package/src/cesium/CesiumLayer.ts +365 -0
  21. package/src/cesium/CesiumMap.ts +363 -347
  22. package/src/cesium/CesiumModel.ts +64 -0
  23. package/src/cesium/CesiumPoint.ts +3 -0
  24. package/src/cesium/CesiumPolygon.ts +2 -0
  25. package/src/cesium/CesiumPolyline.ts +185 -47
  26. package/src/cesium/CesiumTile3D.ts +222 -225
  27. package/src/mine/MineEvent.ts +70 -46
  28. package/src/mine/MineMap.ts +217 -125
  29. package/src/mine/MinePoint.ts +7 -1
  30. package/src/mine/MinePolygon.ts +6 -1
  31. package/src/mine/MinePolyline.ts +6 -1
  32. package/src/openlayer/OpenlayerEvent.ts +109 -87
  33. package/src/openlayer/OpenlayerMap.ts +33 -6
  34. package/src/openlayer/OpenlayerPoint.ts +6 -1
  35. package/src/openlayer/OpenlayerPolygon.ts +6 -1
  36. package/src/openlayer/OpenlayerPolyline.ts +8 -1
  37. package/src/utils/color.ts +49 -0
  38. package/src/utils/index.ts +3 -0
  39. package/src/utils/points-viewer.ts +27 -1
  40. package/src/utils/turfjs-utils.ts +52 -0
  41. package/src/utils/types.d.ts +12 -0
@@ -0,0 +1,365 @@
1
+ import { Layer } from "../basic/Layer";
2
+ import { CesiumMap } from "./CesiumMap";
3
+ import { arrayFillByLen } from "../utils";
4
+ import { LayerOption } from "../basic/Layer";
5
+
6
+ /**
7
+ * 创建影像提供器
8
+ * @param layer
9
+ * @returns
10
+ */
11
+ function createImageryProvider(layer: Layer) {
12
+ const options = layer._option as LayerOption;
13
+
14
+ // 创建 URL 模板影像提供器
15
+ const imageryProvider = new Cesium.UrlTemplateImageryProvider({
16
+ url: options.src,
17
+ maximumLevel: options.maxZoom || 22,
18
+ minimumLevel: options.minZoom || 0,
19
+ });
20
+
21
+ return imageryProvider;
22
+ }
23
+
24
+ /**
25
+ * 更新变换矩阵
26
+ * @param imageryProvider
27
+ * @param layer
28
+ * @param origin
29
+ * @returns
30
+ */
31
+ function updateTransform(imageryProvider: any, layer: Layer, origin: any) {
32
+ const options = layer._option as LayerOption;
33
+
34
+ // 获取影像提供器的边界球中心作为变换原点
35
+ let transformOrigin = origin;
36
+ if (!transformOrigin) {
37
+ const cartographic = Cesium.Cartographic.fromCartesian(imageryProvider.boundingSphere.center);
38
+ transformOrigin = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
39
+ }
40
+
41
+ // 重置模型矩阵
42
+ imageryProvider.modelMatrix = Cesium.Matrix4.IDENTITY.clone();
43
+
44
+ // 1. 位移到目标位置(如果有坐标)
45
+ if (layer.coordinates && layer.coordinates.length >= 2) {
46
+ const [lng, lat, height = 0] = layer.coordinates;
47
+ const target = Cesium.Cartesian3.fromDegrees(lng, lat, height);
48
+ const offset = Cesium.Cartesian3.subtract(target, transformOrigin, new Cesium.Cartesian3());
49
+ const translateMatrix = Cesium.Matrix4.fromTranslation(offset);
50
+ imageryProvider.modelMatrix = Cesium.Matrix4.multiply(
51
+ translateMatrix,
52
+ imageryProvider.modelMatrix,
53
+ new Cesium.Matrix4(),
54
+ );
55
+ }
56
+
57
+ // 2. 应用旋转(本地 ENU 坐标系)
58
+ if (Array.isArray(options.rotates)) {
59
+ const rotates: [number, number, number] = arrayFillByLen([...options.rotates], 3, 0);
60
+ const [rx, ry, rz] = rotates;
61
+ if (rx !== 0 || ry !== 0 || rz !== 0) {
62
+ applyRotation(rx, ry, rz, imageryProvider, transformOrigin);
63
+ }
64
+ }
65
+
66
+ // 3. 应用平移(本地 ENU 坐标系)
67
+ if (options.translates) {
68
+ const translates: [number, number, number] = arrayFillByLen([...options.translates], 3, 0);
69
+ const [dx, dy, dz] = translates;
70
+ if (dx !== 0 || dy !== 0 || dz !== 0) {
71
+ applyTranslation(dx, dy, dz, imageryProvider, transformOrigin);
72
+ }
73
+ }
74
+
75
+ // 4. 应用缩放(本地 ENU 坐标系)
76
+ if (options.scales) {
77
+ const scales: [number, number, number] = arrayFillByLen([...options.scales], 3, 1);
78
+ const [sx, sy, sz] = scales;
79
+ if (sx !== 1 || sy !== 1 || sz !== 1) {
80
+ applyScale(sx, sy, sz, imageryProvider, transformOrigin);
81
+ }
82
+ }
83
+
84
+ return imageryProvider.modelMatrix;
85
+ }
86
+
87
+ // ============= 变换函数 =============
88
+
89
+ /**
90
+ * 基于本地 ENU 坐标系的平移
91
+ * ENU: E(东) - X, N(北) - Y, U(上) - Z
92
+ */
93
+ function applyTranslation(dx: number, dy: number, dz: number, entity: any, origin: any) {
94
+ if (dx === 0 && dy === 0 && dz === 0) return;
95
+
96
+ const { Cartesian3, Matrix4, Transforms } = Cesium;
97
+
98
+ const toWorldMatrix = Transforms.eastNorthUpToFixedFrame(origin);
99
+ const translatePosition = new Cartesian3(dx, dy, dz);
100
+ const worldPosition = Matrix4.multiplyByPoint(toWorldMatrix, translatePosition, new Cartesian3());
101
+ const offset = Cartesian3.subtract(worldPosition, origin, new Cartesian3());
102
+ const translateMatrix = Matrix4.fromTranslation(offset);
103
+
104
+ entity.modelMatrix = Matrix4.multiply(translateMatrix, entity.modelMatrix, new Matrix4());
105
+ }
106
+
107
+ /**
108
+ * 基于本地 ENU 坐标系的旋转
109
+ */
110
+ function applyRotation(rx: number, ry: number, rz: number, entity: any, origin: any) {
111
+ if (rx === 0 && ry === 0 && rz === 0) return;
112
+
113
+ const { Matrix3, Matrix4, Transforms, Math: CesiumMath } = Cesium;
114
+
115
+ const toWorldMatrix = Transforms.eastNorthUpToFixedFrame(origin);
116
+ const toLocalMatrix = Matrix4.inverse(toWorldMatrix, new Matrix4());
117
+
118
+ let rotateMatrix = Matrix4.clone(Matrix4.IDENTITY);
119
+ if (rx !== 0) {
120
+ const m = Matrix4.fromRotationTranslation(Matrix3.fromRotationX(CesiumMath.toRadians(rx)));
121
+ Matrix4.multiply(m, rotateMatrix, rotateMatrix);
122
+ }
123
+ if (ry !== 0) {
124
+ const m = Matrix4.fromRotationTranslation(Matrix3.fromRotationY(CesiumMath.toRadians(ry)));
125
+ Matrix4.multiply(m, rotateMatrix, rotateMatrix);
126
+ }
127
+ if (rz !== 0) {
128
+ const m = Matrix4.fromRotationTranslation(Matrix3.fromRotationZ(CesiumMath.toRadians(rz)));
129
+ Matrix4.multiply(m, rotateMatrix, rotateMatrix);
130
+ }
131
+
132
+ const localResult = Matrix4.multiply(rotateMatrix, toLocalMatrix, new Matrix4());
133
+ const worldResult = Matrix4.multiply(toWorldMatrix, localResult, new Matrix4());
134
+
135
+ entity.modelMatrix = Matrix4.multiply(worldResult, entity.modelMatrix, new Matrix4());
136
+ }
137
+
138
+ /**
139
+ * 基于本地 ENU 坐标系的缩放
140
+ */
141
+ function applyScale(sx: number, sy: number, sz: number, entity: any, origin: any) {
142
+ if (sx <= 0 || sy <= 0 || sz <= 0) throw Error("缩放倍数必须大于0");
143
+ if (sx === 1 && sy === 1 && sz === 1) return;
144
+
145
+ const { Cartesian3, Matrix4, Transforms } = Cesium;
146
+
147
+ const toWorldMatrix = Transforms.eastNorthUpToFixedFrame(origin);
148
+ const toLocalMatrix = Matrix4.inverse(toWorldMatrix, new Matrix4());
149
+ const scaleMatrix = Matrix4.fromScale(new Cartesian3(sx, sy, sz));
150
+
151
+ const localResult = Matrix4.multiply(scaleMatrix, toLocalMatrix, new Matrix4());
152
+ const worldResult = Matrix4.multiply(toWorldMatrix, localResult, new Matrix4());
153
+
154
+ entity.modelMatrix = Matrix4.multiply(worldResult, entity.modelMatrix, new Matrix4());
155
+ }
156
+
157
+ // ============= 计算边界球中心 =============
158
+ function getTransformOrigin(imageryProvider: any) {
159
+ try {
160
+ if (imageryProvider.boundingSphere) {
161
+ const cartographic = Cesium.Cartographic.fromCartesian(imageryProvider.boundingSphere.center);
162
+ return Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height || 0);
163
+ }
164
+
165
+ if (imageryProvider.rectangle) {
166
+ const rect = imageryProvider.rectangle;
167
+ const centerLng = (rect.west + rect.east) / 2;
168
+ const centerLat = (rect.south + rect.north) / 2;
169
+ return Cesium.Cartesian3.fromRadians(centerLng, centerLat, 0);
170
+ }
171
+
172
+ return Cesium.Cartesian3.ZERO;
173
+ } catch (e) {
174
+ console.warn("获取变换原点失败,使用默认原点", e);
175
+ return Cesium.Cartesian3.ZERO;
176
+ }
177
+ }
178
+
179
+ // ============= 安全获取 readyPromise =============
180
+ function getReadyPromise(provider: any): Promise<any> {
181
+ // 如果 provider 有 readyPromise,使用它
182
+ if (provider.readyPromise && typeof provider.readyPromise.then === "function") {
183
+ return provider.readyPromise;
184
+ }
185
+ // 如果 provider 已经 ready,立即返回
186
+ if (provider.ready) {
187
+ return Promise.resolve(provider);
188
+ }
189
+ // 否则轮询等待
190
+ return new Promise((resolve, reject) => {
191
+ const checkReady = () => {
192
+ if (provider.ready) {
193
+ resolve(provider);
194
+ } else if (provider._error) {
195
+ reject(provider._error);
196
+ } else {
197
+ setTimeout(checkReady, 100);
198
+ }
199
+ };
200
+ checkReady();
201
+ });
202
+ }
203
+
204
+ // ============= 主绘制函数 =============
205
+ export function drawLayer(map: CesiumMap, layer: Layer) {
206
+ const { viewer } = map;
207
+ let imageryProvider = createImageryProvider(layer);
208
+ let origin;
209
+ let initialMatrix;
210
+ let isReady = false;
211
+
212
+ // 添加到影像图层
213
+ const imageryLayer = viewer.scene.imageryLayers.addImageryProvider(imageryProvider);
214
+
215
+ // ============= 初始化函数 =============
216
+ function initialize() {
217
+ try {
218
+ origin = getTransformOrigin(imageryProvider);
219
+ initialMatrix = Cesium.Matrix4.clone(imageryProvider.modelMatrix || Cesium.Matrix4.IDENTITY);
220
+ updateTransform(imageryProvider, layer, origin);
221
+ isReady = true;
222
+ layer.event.trigger("ready");
223
+ } catch (error) {
224
+ console.error("影像初始化失败:", error);
225
+ }
226
+ }
227
+
228
+ // 等待影像加载完成
229
+ getReadyPromise(imageryProvider)
230
+ .then(() => {
231
+ initialize();
232
+ })
233
+ .catch((error: any) => {
234
+ console.error("影像加载失败:", error);
235
+ // 即使加载失败,也尝试初始化(可能部分显示)
236
+ initialize();
237
+ });
238
+
239
+ // ============= 更新事件 =============
240
+ const onUpdate = (e: Set<string>) => {
241
+ e.forEach((key) => {
242
+ switch (key) {
243
+ case "show":
244
+ imageryLayer.show = layer.show !== false;
245
+ break;
246
+
247
+ case "src":
248
+ // 重新加载影像
249
+ viewer.scene.imageryLayers.remove(imageryLayer);
250
+ imageryProvider = createImageryProvider(layer);
251
+ const newLayer = viewer.scene.imageryLayers.addImageryProvider(imageryProvider);
252
+
253
+ getReadyPromise(imageryProvider)
254
+ .then(() => {
255
+ origin = getTransformOrigin(imageryProvider);
256
+ initialMatrix = Cesium.Matrix4.clone(imageryProvider.modelMatrix || Cesium.Matrix4.IDENTITY);
257
+ updateTransform(imageryProvider, layer, origin);
258
+ isReady = true;
259
+ layer.event.trigger("ready");
260
+ })
261
+ .catch((error: any) => {
262
+ console.error("重新加载影像失败:", error);
263
+ });
264
+ break;
265
+
266
+ case "coordinates":
267
+ if (!e.has("src") && isReady) {
268
+ updateTransform(imageryProvider, layer, origin);
269
+ }
270
+ break;
271
+
272
+ case "quality":
273
+ const quality = layer.quality || 0.5;
274
+ if (imageryProvider.maximumScreenSpaceError !== undefined) {
275
+ imageryProvider.maximumScreenSpaceError = 18 * (1 - quality * 0.8);
276
+ }
277
+ break;
278
+
279
+ case "opacity":
280
+ imageryLayer.alpha = layer.opacity || 1.0;
281
+ break;
282
+
283
+ default:
284
+ console.warn(`属性 ${key} 暂不支持动态修改`);
285
+ }
286
+ });
287
+ };
288
+
289
+ // ============= 聚焦 =============
290
+ const onFocus = () => {
291
+ if (imageryProvider.rectangle) {
292
+ viewer.camera.flyTo({
293
+ destination: imageryProvider.rectangle,
294
+ duration: 2.0,
295
+ });
296
+ } else if (imageryProvider.boundingSphere) {
297
+ viewer.camera.flyTo({
298
+ destination: imageryProvider.boundingSphere.center,
299
+ duration: 2.0,
300
+ offset: new Cesium.HeadingPitchRange(0, -Math.PI / 4, 1000),
301
+ });
302
+ }
303
+ };
304
+
305
+ // ============= 销毁 =============
306
+ const onDestroy = () => {
307
+ viewer.scene.imageryLayers.remove(imageryLayer);
308
+ layer.event.off("update", onUpdate);
309
+ layer.event.off("focus", onFocus);
310
+ layer.event.off("destroy", onDestroy);
311
+ };
312
+
313
+ // ============= 暴露变换方法 =============
314
+ layer.tileset = imageryProvider;
315
+
316
+ const ensureReady = (fn: Function) => {
317
+ return getReadyPromise(imageryProvider)
318
+ .then(() => {
319
+ if (!initialMatrix) {
320
+ initialMatrix = Cesium.Matrix4.clone(imageryProvider.modelMatrix || Cesium.Matrix4.IDENTITY);
321
+ }
322
+ // 重置到初始状态
323
+ imageryProvider.modelMatrix = Cesium.Matrix4.clone(initialMatrix);
324
+ // 应用变换
325
+ fn();
326
+ // 更新初始矩阵
327
+ initialMatrix = Cesium.Matrix4.clone(imageryProvider.modelMatrix);
328
+ isReady = true;
329
+ })
330
+ .catch((error: any) => {
331
+ console.error("变换失败:", error);
332
+ throw error;
333
+ });
334
+ };
335
+
336
+ layer.translate = function (dx: number, dy: number, dz: number, _tileset?: any) {
337
+ return ensureReady(() => {
338
+ applyTranslation(dx, dy, dz, _tileset || imageryProvider, origin);
339
+ });
340
+ };
341
+
342
+ layer.rotate = function (rx: number, ry: number, rz: number, _tileset?: any) {
343
+ return ensureReady(() => {
344
+ applyRotation(rx, ry, rz, _tileset || imageryProvider, origin);
345
+ });
346
+ };
347
+
348
+ layer.scale = function (sx: number, sy: number, sz: number, _tileset?: any) {
349
+ return ensureReady(() => {
350
+ applyScale(sx, sy, sz, _tileset || imageryProvider, origin);
351
+ });
352
+ };
353
+
354
+ // ============= 注册事件 =============
355
+ layer.event.on("update", onUpdate);
356
+ layer.event.on("focus", onFocus);
357
+ layer.event.on("destroy", onDestroy);
358
+
359
+ // ============= 设置初始透明度 =============
360
+ if (layer.opacity !== undefined) {
361
+ imageryLayer.alpha = layer.opacity;
362
+ }
363
+
364
+ return imageryLayer;
365
+ }