fix: 新增态 效果

This commit is contained in:
Daniel
2026-03-05 15:53:10 +08:00
parent a3bf8abda5
commit af59d6367f
16 changed files with 1334 additions and 113 deletions

106
src/utils/defenseLine.ts Normal file
View File

@@ -0,0 +1,106 @@
/**
* 战场防御线:反弓曲线路径 + 锯齿齿形
*/
export type LngLat = [number, number]
/** 二次贝塞尔 B(t) = (1-t)²P0 + 2(1-t)t P1 + t² P2 */
function quadraticBezier(P0: LngLat, P1: LngLat, P2: LngLat, t: number): LngLat {
const u = 1 - t
return [
u * u * P0[0] + 2 * u * t * P1[0] + t * t * P2[0],
u * u * P0[1] + 2 * u * t * P1[1] + t * t * P2[1],
]
}
/**
* 生成反弓曲线路径:通过 path 各点,弧面向进攻方向(西侧)凸出
* @param path 关键点 [[lng, lat], ...](如大不里士→萨南达季→克尔曼沙赫)
* @param bulgeWest 向西凸出量(经度,正值表示弧顶在西侧/面向进攻方)
* @param samplesPerSegment 每段贝塞尔采样点数
*/
export function createCurvedDefensePath(
path: LngLat[],
bulgeWest: number = 0.35,
samplesPerSegment: number = 24
): LngLat[] {
if (path.length < 2) return path
const out: LngLat[] = []
for (let i = 0; i < path.length - 1; i++) {
const a = path[i]
const b = path[i + 1]
const midLng = (a[0] + b[0]) / 2
const midLat = (a[1] + b[1]) / 2
const control: LngLat = [midLng - bulgeWest, midLat]
const startK = i === 0 ? 0 : 1
for (let k = startK; k <= samplesPerSegment; k++) {
out.push(quadraticBezier(a, control, b, k / samplesPerSegment))
}
}
return out
}
/**
* 沿路径线性插值增加点(直线段)
*/
export function interpolatePath(path: LngLat[], stepsPerSegment: number = 4): LngLat[] {
if (path.length < 2) return path
const out: LngLat[] = []
for (let i = 0; i < path.length - 1; i++) {
const a = path[i]
const b = path[i + 1]
const startK = i === 0 ? 0 : 1
for (let k = startK; k <= stepsPerSegment; k++) {
const t = k / stepsPerSegment
out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t])
}
}
return out
}
/**
* 锯齿防御线:沿 path 每 toothWidth比例生成齿齿高 toothHeight朝向法向敌方侧
* @param path 路径点 [[lng, lat], ...](可先经 interpolatePath 插值)
* @param toothWidth 齿宽(与段长同单位,经纬度)
* @param toothHeight 齿高(法向伸出)
*/
export function createDefenseLine(
path: number[][],
toothWidth: number,
toothHeight: number
): number[][] {
const coords: number[][] = []
for (let i = 0; i < path.length - 1; i++) {
const start = path[i] as [number, number]
const end = path[i + 1] as [number, number]
const dx = end[0] - start[0]
const dy = end[1] - start[1]
const L = Math.sqrt(dx * dx + dy * dy)
if (L < 1e-9) continue
const ux = dx / L
const uy = dy / L
const nx = -uy
const ny = ux
const numTeeth = Math.max(1, Math.floor(L / toothWidth))
const actualWidth = L / numTeeth
for (let j = 0; j < numTeeth; j++) {
const t1 = j * actualWidth
const t2 = t1 + actualWidth * 0.5
const t3 = (j + 1) * actualWidth
coords.push([start[0] + ux * t1, start[1] + uy * t1])
coords.push([
start[0] + ux * t2 + nx * toothHeight,
start[1] + uy * t2 + ny * toothHeight,
])
coords.push([start[0] + ux * t3, start[1] + uy * t3])
}
}
coords.push(path[path.length - 1] as [number, number])
return coords
}