| | |
| | | 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; |