diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index d44aef4..6f9b205 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -899,13 +899,18 @@ export default { if (existingPlatform) { this.viewer.entities.remove(existingPlatform); } - // 清理所有属于该航线的旧点 + // 清理所有属于该航线的旧点(含转弯半径两侧的 entry/exit 点) waypoints.forEach((wp,index) => { const waypointEntityId = `wp_${routeId}_${wp.id}`; const existingWaypoint = this.viewer.entities.getById(waypointEntityId); if (existingWaypoint) { this.viewer.entities.remove(existingWaypoint); } + ['_entry', '_exit'].forEach(suffix => { + const entryExitId = `wp_${routeId}_${wp.id}${suffix}`; + const existingEntryExit = this.viewer.entities.getById(entryExitId); + if (existingEntryExit) this.viewer.entities.remove(existingEntryExit); + }); const arcId = `arc-line-${routeId}-${index}`; const existingArc = this.viewer.entities.getById(arcId); if (existingArc) { @@ -923,15 +928,46 @@ export default { const wpColor = wpStyle.color || '#ffffff'; const wpOutline = wpStyle.outlineColor || '#0078FF'; const wpOutlineW = wpStyle.outlineWidth != null ? wpStyle.outlineWidth : 2; - // 遍历并绘制航点标记 + // 航线默认紫色、线宽 3;与主航线一致的线型用于主线和转弯半径弧 + const lineWidth = lineStyle.width != null ? lineStyle.width : 3; + const lineColor = lineStyle.color || '#800080'; + const gapColor = lineStyle.gapColor != null ? lineStyle.gapColor : '#000000'; + const dashLen = lineStyle.dashLength != null ? lineStyle.dashLength : 20; + const useDash = (lineStyle.style || 'dash') === 'dash'; + const lineMaterial = useDash + ? new Cesium.PolylineDashMaterialProperty({ + color: Cesium.Color.fromCssColorString(lineColor), + gapColor: Cesium.Color.fromCssColorString(gapColor), + dashLength: dashLen + }) + : Cesium.Color.fromCssColorString(lineColor); + // 先收集所有航点的世界坐标 const originalPositions = []; - waypoints.forEach((wp, index) => { + waypoints.forEach((wp) => { const lon = parseFloat(wp.lng); const lat = parseFloat(wp.lat); - // 使用 Number 转换 Double 类型 const altValue = Number(wp.alt || 5000); - const pos = Cesium.Cartesian3.fromDegrees(lon, lat, altValue); - originalPositions.push(pos); + originalPositions.push(Cesium.Cartesian3.fromDegrees(lon, lat, altValue)); + }); + // 判断航点 i 是否为“转弯半径”航点(将用弧线两端两个点替代中心点) + const isTurnWaypointWithArc = (i) => { + if (i < 1 || i >= waypoints.length - 1) return false; + const wp = waypoints[i]; + if (this.getWaypointRadius(wp) <= 0) return false; + const nextPos = originalPositions[i + 1]; + let nextLogical = nextPos; + if (this.isHoldWaypoint(waypoints[i + 1])) { + const holdParams = this.parseHoldParams(waypoints[i + 1]); + nextLogical = holdParams && holdParams.radius != null + ? this.getCircleEntryPoint(originalPositions[i + 1], originalPositions[i], holdParams.radius) + : this.getEllipseEntryPoint(originalPositions[i + 1], originalPositions[i], holdParams.semiMajor ?? 500, holdParams.semiMinor ?? 300, ((holdParams.headingDeg || 0) * Math.PI) / 180); + } + return !!nextLogical; + }; + // 遍历并绘制航点标记:转弯半径处不画中心点,改在下面画弧线时画两端两个点 + waypoints.forEach((wp, index) => { + if (isTurnWaypointWithArc(index)) return; + const pos = originalPositions[index]; this.viewer.entities.add({ id: `wp_${routeId}_${wp.id}`, name: wp.name || `WP${index + 1}`, @@ -1047,9 +1083,42 @@ export default { const arcPoints = this.computeArcPositions(lastPos, currPos, nextLogical, radius); this.viewer.entities.add({ id: `arc-line-${routeId}-${i}`, - polyline: { positions: arcPoints, width: 8, material: Cesium.Color.RED, clampToGround: true, zIndex: 20 }, + polyline: { positions: arcPoints, width: lineWidth, material: lineMaterial, clampToGround: true, zIndex: 20 }, properties: { routeId: routeId } }); + // 转弯半径两侧航点与航线整体航点风格一致,点击均打开原航点编辑(dbId 为当前 wp.id) + const wpName = wp.name || `WP${i + 1}`; + const arcEntry = arcPoints[0]; + const arcExit = arcPoints[arcPoints.length - 1]; + [arcEntry, arcExit].forEach((pos, idx) => { + const suffix = idx === 0 ? '_entry' : '_exit'; + this.viewer.entities.add({ + id: `wp_${routeId}_${wp.id}${suffix}`, + name: wpName, + position: pos, + properties: { + isMissionWaypoint: true, + routeId: routeId, + dbId: wp.id, + }, + point: { + pixelSize: pixelSize, + color: Cesium.Color.fromCssColorString(wpColor), + outlineColor: Cesium.Color.fromCssColorString(wpOutline), + outlineWidth: wpOutlineW, + disableDepthTestDistance: Number.POSITIVE_INFINITY + }, + label: { + text: wpName, + font: `${Math.max(9, pixelSize + 2)}px MicroSoft YaHei`, + pixelOffset: new Cesium.Cartesian2(0, -Math.max(14, pixelSize + 8)), + fillColor: Cesium.Color.WHITE, + outlineColor: Cesium.Color.BLACK, + outlineWidth: 2, + style: Cesium.LabelStyle.FILL_AND_OUTLINE + } + }); + }); finalPathPositions.push(...arcPoints); lastPos = arcPoints[arcPoints.length - 1]; } else { @@ -1058,19 +1127,7 @@ export default { } } } - const lineWidth = lineStyle.width != null ? lineStyle.width : 4; - const lineColor = lineStyle.color || '#ffffff'; - const gapColor = lineStyle.gapColor != null ? lineStyle.gapColor : '#000000'; - const dashLen = lineStyle.dashLength != null ? lineStyle.dashLength : 20; - const useDash = (lineStyle.style || 'dash') === 'dash'; - const lineMaterial = useDash - ? new Cesium.PolylineDashMaterialProperty({ - color: Cesium.Color.fromCssColorString(lineColor), - gapColor: Cesium.Color.fromCssColorString(gapColor), - dashLength: dashLen - }) - : Cesium.Color.fromCssColorString(lineColor); - // 绘制包含弧线的 Polyline + // 绘制包含弧线的 Polyline(lineWidth/lineMaterial 已在上方与航点样式一起计算,默认紫色线宽3) const routeEntity = this.viewer.entities.add({ id: lineId, polyline: {