|
|
|
@ -1716,25 +1716,70 @@ export default { |
|
|
|
effectiveTime[i + 1] = Math.max(actualArrival, scheduled); |
|
|
|
const posCur = { lng: points[i].lng, lat: points[i].lat, alt: points[i].alt }; |
|
|
|
const posNext = { lng: points[i + 1].lng, lat: points[i + 1].lat, alt: points[i + 1].alt }; |
|
|
|
segments.push({ startTime: effectiveTime[i], endTime: actualArrival, startPos: posCur, endPos: posNext, type: 'fly' }); |
|
|
|
segments.push({ startTime: effectiveTime[i], endTime: actualArrival, startPos: posCur, endPos: posNext, type: 'fly', legIndex: i }); |
|
|
|
if (actualArrival < effectiveTime[i + 1]) { |
|
|
|
segments.push({ startTime: actualArrival, endTime: effectiveTime[i + 1], startPos: posNext, endPos: posNext, type: 'wait' }); |
|
|
|
segments.push({ startTime: actualArrival, endTime: effectiveTime[i + 1], startPos: posNext, endPos: posNext, type: 'wait', legIndex: i }); |
|
|
|
} |
|
|
|
} |
|
|
|
return { segments, warnings }; |
|
|
|
}, |
|
|
|
|
|
|
|
/** 从时间轴中取当前推演时间对应的位置 */ |
|
|
|
getPositionFromTimeline(segments, minutesFromK) { |
|
|
|
/** 从路径片段中按比例 t(0~1)取点:按弧长比例插值 */ |
|
|
|
getPositionAlongPathSlice(pathSlice, t) { |
|
|
|
if (!pathSlice || pathSlice.length === 0) return null; |
|
|
|
if (pathSlice.length === 1 || t <= 0) return pathSlice[0]; |
|
|
|
if (t >= 1) return pathSlice[pathSlice.length - 1]; |
|
|
|
let totalLen = 0; |
|
|
|
const lengths = [0]; |
|
|
|
for (let i = 1; i < pathSlice.length; i++) { |
|
|
|
totalLen += this.segmentDistance(pathSlice[i - 1], pathSlice[i]); |
|
|
|
lengths.push(totalLen); |
|
|
|
} |
|
|
|
const targetDist = t * totalLen; |
|
|
|
let idx = 0; |
|
|
|
while (idx < lengths.length - 1 && lengths[idx + 1] < targetDist) idx++; |
|
|
|
const a = pathSlice[idx]; |
|
|
|
const b = pathSlice[idx + 1]; |
|
|
|
const segLen = lengths[idx + 1] - lengths[idx]; |
|
|
|
const segT = segLen > 0 ? (targetDist - lengths[idx]) / segLen : 0; |
|
|
|
return { |
|
|
|
lng: a.lng + (b.lng - a.lng) * segT, |
|
|
|
lat: a.lat + (b.lat - a.lat) * segT, |
|
|
|
alt: a.alt + (b.alt - a.alt) * segT |
|
|
|
}; |
|
|
|
}, |
|
|
|
|
|
|
|
/** 从时间轴中取当前推演时间对应的位置;若有 path/segmentEndIndices 则沿带转弯弧的路径插值 */ |
|
|
|
getPositionFromTimeline(segments, minutesFromK, path, segmentEndIndices) { |
|
|
|
if (!segments || segments.length === 0) return null; |
|
|
|
if (minutesFromK <= segments[0].startTime) return segments[0].startPos; |
|
|
|
const last = segments[segments.length - 1]; |
|
|
|
if (minutesFromK >= last.endTime) return last.endPos; |
|
|
|
if (minutesFromK >= last.endTime) { |
|
|
|
// 若最后一段是等待且有弧线路径,终点取弧线终点 |
|
|
|
if (last.type === 'wait' && path && segmentEndIndices && last.legIndex != null && last.legIndex < segmentEndIndices.length && path[segmentEndIndices[last.legIndex]]) { |
|
|
|
return path[segmentEndIndices[last.legIndex]]; |
|
|
|
} |
|
|
|
return last.endPos; |
|
|
|
} |
|
|
|
for (let i = 0; i < segments.length; i++) { |
|
|
|
const s = segments[i]; |
|
|
|
if (minutesFromK < s.endTime) { |
|
|
|
const t = (minutesFromK - s.startTime) / (s.endTime - s.startTime); |
|
|
|
if (s.type === 'wait') return s.startPos; |
|
|
|
if (s.type === 'wait') { |
|
|
|
// 有弧线路径时在弧线终点等待,不跳到航点 |
|
|
|
if (path && segmentEndIndices && s.legIndex != null && s.legIndex < segmentEndIndices.length) { |
|
|
|
const endIdx = segmentEndIndices[s.legIndex]; |
|
|
|
if (path[endIdx]) return path[endIdx]; |
|
|
|
} |
|
|
|
return s.startPos; |
|
|
|
} |
|
|
|
// 有带弧路径且当前为飞行段且存在对应航段索引时,沿路径弧线插值(含上一段终点,保证从弧线终点匀速运动到本段终点、不闪现) |
|
|
|
if (path && segmentEndIndices && s.legIndex != null && s.legIndex < segmentEndIndices.length) { |
|
|
|
const startIdx = s.legIndex === 0 ? 0 : segmentEndIndices[s.legIndex - 1]; |
|
|
|
const endIdx = segmentEndIndices[s.legIndex]; |
|
|
|
const pathSlice = path.slice(startIdx, endIdx + 1); |
|
|
|
if (pathSlice.length > 0) return this.getPositionAlongPathSlice(pathSlice, t); |
|
|
|
} |
|
|
|
return { |
|
|
|
lng: s.startPos.lng + (s.endPos.lng - s.startPos.lng) * t, |
|
|
|
lat: s.startPos.lat + (s.endPos.lat - s.startPos.lat) * t, |
|
|
|
@ -1745,12 +1790,24 @@ export default { |
|
|
|
return last.endPos; |
|
|
|
}, |
|
|
|
|
|
|
|
/** 根据当前推演时间(相对 K 的分钟)得到平台位置,使用速度与等待逻辑;返回 { position, warnings } */ |
|
|
|
/** 根据当前推演时间(相对 K 的分钟)得到平台位置,使用速度与等待逻辑;若有地图 ref 则沿转弯弧路径运动;返回 { position, nextPosition, previousPosition, warnings },用于计算机头朝向 */ |
|
|
|
getPositionAtMinutesFromK(waypoints, minutesFromK, globalMin, globalMax) { |
|
|
|
if (!waypoints || waypoints.length === 0) return { position: null, warnings: [] }; |
|
|
|
if (!waypoints || waypoints.length === 0) return { position: null, nextPosition: null, previousPosition: null, warnings: [] }; |
|
|
|
const { segments, warnings } = this.buildRouteTimeline(waypoints, globalMin, globalMax); |
|
|
|
const position = this.getPositionFromTimeline(segments, minutesFromK); |
|
|
|
return { position, warnings }; |
|
|
|
let path = null; |
|
|
|
let segmentEndIndices = null; |
|
|
|
if (this.$refs.cesiumMap && this.$refs.cesiumMap.getRoutePathWithSegmentIndices) { |
|
|
|
const ret = this.$refs.cesiumMap.getRoutePathWithSegmentIndices(waypoints); |
|
|
|
if (ret.path && ret.path.length > 0 && ret.segmentEndIndices && ret.segmentEndIndices.length > 0) { |
|
|
|
path = ret.path; |
|
|
|
segmentEndIndices = ret.segmentEndIndices; |
|
|
|
} |
|
|
|
} |
|
|
|
const position = this.getPositionFromTimeline(segments, minutesFromK, path, segmentEndIndices); |
|
|
|
const stepMin = 1 / 60; |
|
|
|
const nextPosition = this.getPositionFromTimeline(segments, minutesFromK + stepMin, path, segmentEndIndices); |
|
|
|
const previousPosition = this.getPositionFromTimeline(segments, minutesFromK - stepMin, path, segmentEndIndices); |
|
|
|
return { position, nextPosition, previousPosition, warnings }; |
|
|
|
}, |
|
|
|
|
|
|
|
/** 仅根据当前展示的航线(activeRouteIds)更新平台图标位置,并汇总航段提示 */ |
|
|
|
@ -1762,9 +1819,9 @@ export default { |
|
|
|
this.activeRouteIds.forEach(routeId => { |
|
|
|
const route = this.routes.find(r => r.id === routeId); |
|
|
|
if (!route || !route.waypoints || route.waypoints.length === 0) return; |
|
|
|
const { position, warnings } = this.getPositionAtMinutesFromK(route.waypoints, minutesFromK, minMinutes, maxMinutes); |
|
|
|
const { position, nextPosition, previousPosition, warnings } = this.getPositionAtMinutesFromK(route.waypoints, minutesFromK, minMinutes, maxMinutes); |
|
|
|
if (warnings && warnings.length) allWarnings.push(...warnings); |
|
|
|
if (position) this.$refs.cesiumMap.updatePlatformPosition(routeId, position); |
|
|
|
if (position) this.$refs.cesiumMap.updatePlatformPosition(routeId, position, nextPosition || previousPosition); |
|
|
|
}); |
|
|
|
this.deductionWarnings = [...new Set(allWarnings)]; |
|
|
|
}, |
|
|
|
|