refactor(地图几何计算): 重构线段投影距离计算逻辑
将 lineSignedRemainAlong 函数从 MapCanvas 组件移至 mapTrackGeometry 工具模块
简化 calcSignedSegmentDelta 函数中的环形轨道判断逻辑
使用工具模块中的几何计算函数替代重复实现
| | |
| | | calcSignedSegmentDelta(fromBarcode, toBarcode, trackInfo, totalSegmentCount) { |
| | | const from = Number(fromBarcode); |
| | | const to = Number(toBarcode); |
| | | if (!isFinite(from) || !isFinite(to)) { |
| | | return 0; |
| | | } |
| | | if (!isFinite(from) || !isFinite(to)) return 0; |
| | | const raw = to - from; |
| | | if (trackInfo.type !== 'annulus') { |
| | | return raw; |
| | | } |
| | | const span = totalSegmentCount; |
| | | if (!(span > 0)) { |
| | | return raw; |
| | | } |
| | | const mod = (n, m) => ((n % m) + m) % m; |
| | | return mod(raw, span); |
| | | }, |
| | | lineSignedRemainAlong(path0, sx, sy, mx, my) { |
| | | if (!path0 || path0.type !== 'line') { |
| | | return null; |
| | | } |
| | | const x0 = path0.startX; |
| | | const y0 = path0.startY; |
| | | const vx = path0.x - x0; |
| | | const vy = path0.y - y0; |
| | | const segLen = Math.sqrt(vx * vx + vy * vy); |
| | | if (!(segLen > EPSILON)) { |
| | | return null; |
| | | } |
| | | const clampT = (px, py) => { |
| | | const t = ((px - x0) * vx + (py - y0) * vy) / segLen; |
| | | return Math.max(0, Math.min(segLen, t)); |
| | | }; |
| | | return clampT(mx, my) - clampT(sx, sy); |
| | | if (trackInfo.type !== 'annulus' || totalSegmentCount <= 0) return raw; |
| | | // 非负取模 |
| | | return ((raw % totalSegmentCount) + totalSegmentCount) % totalSegmentCount; |
| | | }, |
| | | finishDeviceMotion(sprite) { |
| | | if (!sprite || !sprite.mappingInfo) { |
| | |
| | | pathList.length === 1 && pathList[0].type === 'line' && sprite.trackInfo.type !== 'annulus'; |
| | | let smoothDistance; |
| | | if (singleLineTrack) { |
| | | const remainAlong = this.lineSignedRemainAlong( |
| | | const remainAlong = G.lineSignedRemainAlong( |
| | | path, |
| | | sprite.x, |
| | | sprite.y, |
| | |
| | | if (remainAlong != null) { |
| | | let stepMag = Math.min(stepCap, Math.abs(remainAlong), restDistance); |
| | | if (stepMag < EPSILON && restDistance > EPSILON) { |
| | | const x0 = path.startX; |
| | | const y0 = path.startY; |
| | | const vx = path.x - x0; |
| | | const vy = path.y - y0; |
| | | const sl = Math.sqrt(vx * vx + vy * vy); |
| | | const lineStart = { x: path.startX, y: path.startY }; |
| | | const lineEnd = { x: path.x, y: path.y }; |
| | | const sl = G.calcDistance(lineStart, lineEnd); |
| | | if (sl > EPSILON) { |
| | | const ux = vx / sl; |
| | | const uy = vy / sl; |
| | | const { x: ux, y: uy } = G.normalizeVector(lineStart, lineEnd); |
| | | const wdx = sprite.mappingInfo.x - sprite.x; |
| | | const wdy = sprite.mappingInfo.y - sprite.y; |
| | | const hint = wdx * ux + wdy * uy; |
| | |
| | | return count === 2; |
| | | } |
| | | |
| | | /** |
| | | * 计算点 (sx,sy) 和 (mx,my) 在直线段 path0 上的带符号投影距离差。 |
| | | * 返回值 >0 表示 mx,my 在 sx,sy 前方(沿路径方向)。 |
| | | * @param {{ type: string, startX: number, startY: number, x: number, y: number }} path0 直线段路径 |
| | | * @param {number} sx 起点 x |
| | | * @param {number} sy 起点 y |
| | | * @param {number} mx 终点 x |
| | | * @param {number} my 终点 y |
| | | * @returns {number|null} 带符号距离差,非线段或零长度时返回 null |
| | | */ |
| | | function lineSignedRemainAlong(path0, sx, sy, mx, my) { |
| | | if (!path0 || path0.type !== 'line') { |
| | | return null; |
| | | } |
| | | var start = { x: path0.startX, y: path0.startY }; |
| | | var end = { x: path0.x, y: path0.y }; |
| | | var segLen = calcDistance(start, end); |
| | | if (!(segLen > 0)) { |
| | | return null; |
| | | } |
| | | var vector = normalizeVector(start, end); |
| | | var clampT = function (px, py) { |
| | | var t = ((px - start.x) * vector.x + (py - start.y) * vector.y) * segLen; |
| | | return Math.max(0, Math.min(segLen, t)); |
| | | }; |
| | | return clampT(mx, my) - clampT(sx, sy); |
| | | } |
| | | |
| | | function setRadiusInPoint(pointList, sprite) { |
| | | sprite.halfList = []; |
| | | var pointLength = pointList.length; |
| | |
| | | startDrawSmoothedPath: startDrawSmoothedPath, |
| | | getRotate: getRotate, |
| | | drawCrnDeviceGraphics: drawCrnDeviceGraphics, |
| | | drawRgvDeviceGraphics: drawRgvDeviceGraphics |
| | | drawRgvDeviceGraphics: drawRgvDeviceGraphics, |
| | | lineSignedRemainAlong: lineSignedRemainAlong |
| | | }; |
| | | })(typeof window !== 'undefined' ? window : this); |