huweili-cesium 1.0.13 → 1.0.14

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,242 @@
1
+ /**
2
+ * 无人机规划航迹模块
3
+ *
4
+ * 根据前端传入的经纬度+高度数组,在空中绘制航迹连线及航点标注。
5
+ * 无人机实际位置仍由 WebSocket 数据通过 moveDronePoint 驱动。
6
+ */
7
+ import * as Cesium from 'cesium'
8
+ import { useMapStore } from './stores/mapStore.js'
9
+
10
+ const PLANNED_ROUTE_STORE_SUFFIX = '_planned_route'
11
+ const DEFAULT_LINE_COLOR = 'rgba(0, 191, 255, 0.85)'
12
+ const DEFAULT_LINE_WIDTH = 3
13
+
14
+ /**
15
+ * 将前端航点数组规范为 { lng, lat, height }
16
+ * 支持字段:lng/lon/longitude, lat/latitude, height/alt/altitude
17
+ */
18
+ function normalizeWaypoints(waypoints) {
19
+ if (!Array.isArray(waypoints)) return []
20
+
21
+ return waypoints
22
+ .map((wp, index) => {
23
+ const lng = Number(wp?.lng ?? wp?.lon ?? wp?.longitude ?? wp?.LONGITUDE)
24
+ const lat = Number(wp?.lat ?? wp?.latitude ?? wp?.LATITUDE)
25
+ const height = Number(wp?.height ?? wp?.alt ?? wp?.altitude ?? wp?.HEIGHT ?? 0)
26
+ if (!Number.isFinite(lng) || !Number.isFinite(lat)) return null
27
+ return {
28
+ lng,
29
+ lat,
30
+ height: Number.isFinite(height) ? height : 0,
31
+ index,
32
+ }
33
+ })
34
+ .filter(Boolean)
35
+ }
36
+
37
+ function getRouteStoreKey(routeId) {
38
+ return `${routeId}${PLANNED_ROUTE_STORE_SUFFIX}`
39
+ }
40
+
41
+ function removeRouteEntities(map, routeData) {
42
+ if (!map || !routeData) return
43
+
44
+ routeData.entities?.forEach((entity) => {
45
+ if (entity) {
46
+ map.entities.remove(entity)
47
+ }
48
+ })
49
+ routeData.entities = []
50
+ routeData.polylineEntity = null
51
+ }
52
+
53
+ export function dronePlannedRouteConfig() {
54
+ const mapStore = useMapStore()
55
+
56
+ /**
57
+ * 绘制无人机规划航迹(空中折线 + 航点标注)
58
+ * @param {Object} options
59
+ * @param {string} options.routeId 航迹唯一标识,通常与无人机 pointId/uavId 一致
60
+ * @param {string} [options.pointId] 同 routeId,二选一
61
+ * @param {string} options.mapId 地图实例 ID
62
+ * @param {Array<{lng, lat, height}|{longitude, latitude, height}>} options.waypoints 航点数组
63
+ * @param {string} [options.lineColor] 航迹线颜色,默认青色
64
+ * @param {number} [options.lineWidth] 航迹线宽度
65
+ * @param {boolean} [options.showWaypointLabels=true] 是否显示「航点1、航点2…」标签
66
+ * @param {number} [options.waypointPixelSize=10] 航点圆点大小
67
+ * @param {boolean} [options.flyToRoute=false] 绘制后是否飞到航迹范围
68
+ * @returns {Object|null} 航迹数据对象
69
+ */
70
+ const setDronePlannedRoute = (options = {}) => {
71
+ const routeId = options.routeId || options.pointId
72
+ const { mapId, flyToRoute = false } = options
73
+
74
+ if (!routeId) {
75
+ console.warn('setDronePlannedRoute: 缺少 routeId / pointId')
76
+ return null
77
+ }
78
+
79
+ const normalized = normalizeWaypoints(options.waypoints)
80
+ if (normalized.length < 1) {
81
+ console.warn('setDronePlannedRoute: 航点数组为空或无效')
82
+ return null
83
+ }
84
+
85
+ const map = mapStore.getMap(mapId)
86
+ if (!map) {
87
+ console.error('地图实例不存在')
88
+ return null
89
+ }
90
+
91
+ // 已存在则先清除再重建,保证航迹与航点一致
92
+ clearDronePlannedRoute({ routeId, mapId })
93
+
94
+ const lineColor = options.lineColor || DEFAULT_LINE_COLOR
95
+ const lineWidth = Number(options.lineWidth) || DEFAULT_LINE_WIDTH
96
+ const showWaypointLabels = options.showWaypointLabels !== false
97
+ const waypointPixelSize = Number(options.waypointPixelSize) || 10
98
+ const color = Cesium.Color.fromCssColorString(lineColor)
99
+
100
+ const positions = normalized.map((wp) =>
101
+ Cesium.Cartesian3.fromDegrees(wp.lng, wp.lat, wp.height)
102
+ )
103
+
104
+ const routeData = {
105
+ routeId,
106
+ mapId,
107
+ waypoints: normalized,
108
+ entities: [],
109
+ polylineEntity: null,
110
+ isVisible: true,
111
+ }
112
+
113
+ if (normalized.length >= 2) {
114
+ routeData.polylineEntity = map.entities.add({
115
+ id: `${routeId}_planned_route_line`,
116
+ name: `规划航迹:${routeId}`,
117
+ polyline: {
118
+ positions,
119
+ width: lineWidth,
120
+ material: color,
121
+ arcType: Cesium.ArcType.NONE,
122
+ clampToGround: false,
123
+ },
124
+ })
125
+ routeData.entities.push(routeData.polylineEntity)
126
+ }
127
+
128
+ normalized.forEach((wp, i) => {
129
+ const position = Cesium.Cartesian3.fromDegrees(wp.lng, wp.lat, wp.height)
130
+ const waypointEntity = map.entities.add({
131
+ id: `${routeId}_planned_route_wp_${i}`,
132
+ name: `规划航点${i + 1}:${routeId}`,
133
+ position,
134
+ point: {
135
+ pixelSize: waypointPixelSize,
136
+ color,
137
+ outlineColor: Cesium.Color.WHITE,
138
+ outlineWidth: 2,
139
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
140
+ },
141
+ label: showWaypointLabels
142
+ ? {
143
+ text: `航点${i + 1}`,
144
+ font: '14px Microsoft YaHei, sans-serif',
145
+ fillColor: Cesium.Color.WHITE,
146
+ outlineColor: Cesium.Color.BLACK,
147
+ outlineWidth: 2,
148
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
149
+ verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
150
+ pixelOffset: new Cesium.Cartesian2(0, -12),
151
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
152
+ }
153
+ : undefined,
154
+ })
155
+ routeData.entities.push(waypointEntity)
156
+ })
157
+
158
+ routeData.destroy = () => {
159
+ removeRouteEntities(map, routeData)
160
+ mapStore.removeGraphicMap(getRouteStoreKey(routeId), mapId)
161
+ }
162
+
163
+ mapStore.setGraphicMap(getRouteStoreKey(routeId), routeData, mapId)
164
+
165
+ if (flyToRoute && positions.length > 0) {
166
+ const boundingSphere = Cesium.BoundingSphere.fromPoints(positions)
167
+ map.camera.flyToBoundingSphere(boundingSphere, { duration: 1.2 })
168
+ }
169
+
170
+ return routeData
171
+ }
172
+
173
+ /**
174
+ * 更新规划航迹(等价于清除后重新绘制)
175
+ */
176
+ const updateDronePlannedRoute = (options) => setDronePlannedRoute(options)
177
+
178
+ /**
179
+ * 清除规划航迹及航点标注
180
+ * @param {Object} options
181
+ * @param {string} options.routeId 航迹 ID(或 pointId)
182
+ * @param {string} options.mapId 地图实例 ID
183
+ */
184
+ const clearDronePlannedRoute = (options = {}) => {
185
+ const routeId = options.routeId || options.pointId
186
+ const { mapId } = options
187
+
188
+ if (!routeId) {
189
+ console.warn('clearDronePlannedRoute: 缺少 routeId / pointId')
190
+ return false
191
+ }
192
+
193
+ const storeKey = getRouteStoreKey(routeId)
194
+ const routeData = mapStore.getGraphicMap(storeKey, mapId)
195
+ if (!routeData) return false
196
+
197
+ const map = mapStore.getMap(mapId)
198
+ removeRouteEntities(map, routeData)
199
+ mapStore.removeGraphicMap(storeKey, mapId)
200
+ return true
201
+ }
202
+
203
+ /**
204
+ * 显示/隐藏规划航迹
205
+ */
206
+ const toggleDronePlannedRouteVisibility = (options = {}) => {
207
+ const routeId = options.routeId || options.pointId
208
+ const { mapId, visible } = options
209
+
210
+ if (!routeId || visible === undefined) return false
211
+
212
+ const routeData = mapStore.getGraphicMap(getRouteStoreKey(routeId), mapId)
213
+ if (!routeData) {
214
+ console.warn(`规划航迹不存在,ID: ${routeId}`)
215
+ return false
216
+ }
217
+
218
+ routeData.isVisible = visible
219
+ routeData.entities?.forEach((entity) => {
220
+ if (entity) entity.show = visible
221
+ })
222
+ return true
223
+ }
224
+
225
+ /**
226
+ * 获取已绘制的规划航迹数据
227
+ */
228
+ const getDronePlannedRoute = (options = {}) => {
229
+ const routeId = options.routeId || options.pointId
230
+ const { mapId } = options
231
+ if (!routeId) return null
232
+ return mapStore.getGraphicMap(getRouteStoreKey(routeId), mapId) || null
233
+ }
234
+
235
+ return {
236
+ setDronePlannedRoute,
237
+ updateDronePlannedRoute,
238
+ clearDronePlannedRoute,
239
+ toggleDronePlannedRouteVisibility,
240
+ getDronePlannedRoute,
241
+ }
242
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * movePoint 扩展模块(不修改原 movePoint.js)
3
+ *
4
+ * 在原有 movePointConfig 能力基础上,组合规划航迹模块,
5
+ * 并提供同时销毁无人机与规划航迹的方法。
6
+ */
7
+ import { movePointConfig } from './movePoint.js'
8
+ import { dronePlannedRouteConfig } from './dronePlannedRoute.js'
9
+
10
+ export function movePointPlannedRouteConfig(baseUrl) {
11
+ const movePoint = movePointConfig(baseUrl)
12
+ const plannedRoute = dronePlannedRouteConfig()
13
+
14
+ /**
15
+ * 销毁无人机模型、实时轨迹,并清除对应规划航迹
16
+ */
17
+ const destroyDroneTrailAndPlannedRoute = (options) => {
18
+ const result = movePoint.destroyDroneTrail(options)
19
+ plannedRoute.clearDronePlannedRoute({
20
+ routeId: options?.pointId,
21
+ mapId: options?.mapId,
22
+ })
23
+ return result
24
+ }
25
+
26
+ return {
27
+ ...movePoint,
28
+ ...plannedRoute,
29
+ destroyDroneTrailAndPlannedRoute,
30
+ }
31
+ }
package/package.json CHANGED
@@ -1,101 +1,105 @@
1
- {
2
- "name": "huweili-cesium",
3
- "version": "1.0.13",
4
- "description": "基于 Cesium 的地图工具库(无人机态势、轨迹、围栏、工具栏等)",
5
- "type": "module",
6
- "main": "./index.js",
7
- "module": "./index.js",
8
- "exports": {
9
- ".": "./index.js",
10
- "./basis": "./basis.js",
11
- "./basis.js": "./basis.js",
12
- "./captureFenceScreenshot": "./captureFenceScreenshot.js",
13
- "./captureFenceScreenshot.js": "./captureFenceScreenshot.js",
14
- "./cardPool": "./cardPool.js",
15
- "./cardPool.js": "./cardPool.js",
16
- "./clickHandler": "./clickHandler.js",
17
- "./clickHandler.js": "./clickHandler.js",
18
- "./customToolbarButtons": "./customToolbarButtons.js",
19
- "./customToolbarButtons.js": "./customToolbarButtons.js",
20
- "./drawFence": "./drawFence.js",
21
- "./drawFence.js": "./drawFence.js",
22
- "./drawFenceNew": "./drawFenceNew.js",
23
- "./drawFenceNew.js": "./drawFenceNew.js",
24
- "./droneRipple": "./droneRipple.js",
25
- "./droneRipple.js": "./droneRipple.js",
26
- "./geometry": "./geometry.js",
27
- "./geometry.js": "./geometry.js",
28
- "./groundLink": "./groundLink.js",
29
- "./groundLink.js": "./groundLink.js",
30
- "./hemisphere": "./hemisphere.js",
31
- "./hemisphere.js": "./hemisphere.js",
32
- "./labelDiv": "./labelDiv.js",
33
- "./labelDiv.js": "./labelDiv.js",
34
- "./movePath": "./movePath.js",
35
- "./movePath.js": "./movePath.js",
36
- "./movePoint": "./movePoint.js",
37
- "./movePoint.js": "./movePoint.js",
38
- "./qrCodeGenerator": "./qrCodeGenerator.js",
39
- "./qrCodeGenerator.js": "./qrCodeGenerator.js",
40
- "./setPath": "./setPath.js",
41
- "./setPath.js": "./setPath.js",
42
- "./setPoint": "./setPoint.js",
43
- "./setPoint.js": "./setPoint.js",
44
- "./tileProviders": "./tileProviders.js",
45
- "./tileProviders.js": "./tileProviders.js",
46
- "./toolbar/basemapSwitcher": "./toolbar/basemapSwitcher.js",
47
- "./toolbar/basemapSwitcher.js": "./toolbar/basemapSwitcher.js",
48
- "./toolbar/compass": "./toolbar/compass.js",
49
- "./toolbar/compass.js": "./toolbar/compass.js",
50
- "./toolbar/fullscreenController": "./toolbar/fullscreenController.js",
51
- "./toolbar/fullscreenController.js": "./toolbar/fullscreenController.js",
52
- "./toolbar/zoomController": "./toolbar/zoomController.js",
53
- "./toolbar/zoomController.js": "./toolbar/zoomController.js",
54
- "./stores/mapStore": "./stores/mapStore.js",
55
- "./stores/mapStore.js": "./stores/mapStore.js",
56
- "./utils/eventBus": "./utils/eventBus.js",
57
- "./utils/useEventBus": "./utils/useEventBus.js",
58
- "./utils/getMapCenterPosition": "./utils/getMapCenterPosition.js",
59
- "./utils/droneSelection": "./utils/droneSelection.js",
60
- "./config": "./config/index.js",
61
- "./config/index": "./config/index.js",
62
- "./config/hooks": "./config/hooks.js",
63
- "./api/gaode": "./api/gaode.js"
64
- },
65
- "files": [
66
- "*.js",
67
- "toolbar/**/*.js",
68
- "stores/**/*.js",
69
- "utils/**/*.js",
70
- "config/**/*.js",
71
- "api/**/*.js"
72
- ],
73
- "scripts": {
74
- "sync": "node scripts/sync-from-source.mjs",
75
- "prepublishOnly": "node scripts/verify-files.mjs"
76
- },
77
- "keywords": [
78
- "cesium",
79
- "map",
80
- "drone",
81
- "3d",
82
- "gis"
83
- ],
84
- "author": "huweili <czxyhuweili@163.com>",
85
- "license": "MIT",
86
- "repository": {
87
- "type": "git",
88
- "url": ""
89
- },
90
- "peerDependencies": {
91
- "cesium": ">=1.100.0",
92
- "mitt": "^3.0.0",
93
- "pinia": "^2.0.0 || ^3.0.0",
94
- "qrcode": "^1.5.0",
95
- "vue": "^3.3.0"
96
- },
97
- "dependencies": {},
98
- "engines": {
99
- "node": ">=18"
100
- }
101
- }
1
+ {
2
+ "name": "huweili-cesium",
3
+ "version": "1.0.14",
4
+ "description": "基于 Cesium 的地图工具库(无人机态势、轨迹、围栏、工具栏等)",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "module": "./index.js",
8
+ "exports": {
9
+ ".": "./index.js",
10
+ "./basis": "./basis.js",
11
+ "./basis.js": "./basis.js",
12
+ "./captureFenceScreenshot": "./captureFenceScreenshot.js",
13
+ "./captureFenceScreenshot.js": "./captureFenceScreenshot.js",
14
+ "./cardPool": "./cardPool.js",
15
+ "./cardPool.js": "./cardPool.js",
16
+ "./clickHandler": "./clickHandler.js",
17
+ "./clickHandler.js": "./clickHandler.js",
18
+ "./customToolbarButtons": "./customToolbarButtons.js",
19
+ "./customToolbarButtons.js": "./customToolbarButtons.js",
20
+ "./drawFence": "./drawFence.js",
21
+ "./drawFence.js": "./drawFence.js",
22
+ "./drawFenceNew": "./drawFenceNew.js",
23
+ "./drawFenceNew.js": "./drawFenceNew.js",
24
+ "./dronePlannedRoute": "./dronePlannedRoute.js",
25
+ "./dronePlannedRoute.js": "./dronePlannedRoute.js",
26
+ "./droneRipple": "./droneRipple.js",
27
+ "./droneRipple.js": "./droneRipple.js",
28
+ "./geometry": "./geometry.js",
29
+ "./geometry.js": "./geometry.js",
30
+ "./groundLink": "./groundLink.js",
31
+ "./groundLink.js": "./groundLink.js",
32
+ "./hemisphere": "./hemisphere.js",
33
+ "./hemisphere.js": "./hemisphere.js",
34
+ "./labelDiv": "./labelDiv.js",
35
+ "./labelDiv.js": "./labelDiv.js",
36
+ "./movePath": "./movePath.js",
37
+ "./movePath.js": "./movePath.js",
38
+ "./movePoint": "./movePoint.js",
39
+ "./movePoint.js": "./movePoint.js",
40
+ "./movePointPlannedRoute": "./movePointPlannedRoute.js",
41
+ "./movePointPlannedRoute.js": "./movePointPlannedRoute.js",
42
+ "./qrCodeGenerator": "./qrCodeGenerator.js",
43
+ "./qrCodeGenerator.js": "./qrCodeGenerator.js",
44
+ "./setPath": "./setPath.js",
45
+ "./setPath.js": "./setPath.js",
46
+ "./setPoint": "./setPoint.js",
47
+ "./setPoint.js": "./setPoint.js",
48
+ "./tileProviders": "./tileProviders.js",
49
+ "./tileProviders.js": "./tileProviders.js",
50
+ "./toolbar/basemapSwitcher": "./toolbar/basemapSwitcher.js",
51
+ "./toolbar/basemapSwitcher.js": "./toolbar/basemapSwitcher.js",
52
+ "./toolbar/compass": "./toolbar/compass.js",
53
+ "./toolbar/compass.js": "./toolbar/compass.js",
54
+ "./toolbar/fullscreenController": "./toolbar/fullscreenController.js",
55
+ "./toolbar/fullscreenController.js": "./toolbar/fullscreenController.js",
56
+ "./toolbar/zoomController": "./toolbar/zoomController.js",
57
+ "./toolbar/zoomController.js": "./toolbar/zoomController.js",
58
+ "./stores/mapStore": "./stores/mapStore.js",
59
+ "./stores/mapStore.js": "./stores/mapStore.js",
60
+ "./utils/eventBus": "./utils/eventBus.js",
61
+ "./utils/useEventBus": "./utils/useEventBus.js",
62
+ "./utils/getMapCenterPosition": "./utils/getMapCenterPosition.js",
63
+ "./utils/droneSelection": "./utils/droneSelection.js",
64
+ "./config": "./config/index.js",
65
+ "./config/index": "./config/index.js",
66
+ "./config/hooks": "./config/hooks.js",
67
+ "./api/gaode": "./api/gaode.js"
68
+ },
69
+ "files": [
70
+ "*.js",
71
+ "toolbar/**/*.js",
72
+ "stores/**/*.js",
73
+ "utils/**/*.js",
74
+ "config/**/*.js",
75
+ "api/**/*.js"
76
+ ],
77
+ "scripts": {
78
+ "sync": "node scripts/sync-from-source.mjs",
79
+ "prepublishOnly": "node scripts/verify-files.mjs"
80
+ },
81
+ "keywords": [
82
+ "cesium",
83
+ "map",
84
+ "drone",
85
+ "3d",
86
+ "gis"
87
+ ],
88
+ "author": "huweili <czxyhuweili@163.com>",
89
+ "license": "MIT",
90
+ "repository": {
91
+ "type": "git",
92
+ "url": ""
93
+ },
94
+ "peerDependencies": {
95
+ "cesium": ">=1.100.0",
96
+ "mitt": "^3.0.0",
97
+ "pinia": "^2.0.0 || ^3.0.0",
98
+ "qrcode": "^1.5.0",
99
+ "vue": "^3.3.0"
100
+ },
101
+ "dependencies": {},
102
+ "engines": {
103
+ "node": ">=18"
104
+ }
105
+ }