import { Vector2 } from "../Vector2" interface P { x: number y: number } export interface IOffset { negativeOffset: number positiveOffset: number } /** 点p到线段P1P2 的最短距离的平方,线段不延伸 */ function GetSqSegDist(p: P, p1: P, p2: P): number { let x = p1.x let y = p1.y let dx = p2.x - x let dy = p2.y - y if (dx !== 0 || dy !== 0)// 不是0长度线 { const t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy) if (t > 1) { x = p2.x y = p2.y } else if (t > 0) { x += dx * t y += dy * t } } dx = p.x - x dy = p.y - y return dx * dx + dy * dy } function CrossVector2(a: P, b: P) { return a.x * b.y - a.y * b.x } // Ramer-Douglas-Peucker algorithm function SimplifyDPStep(points: P[], first: number, last: number, sqTolerance: number, simplified: P[], offset: IOffset): void { let maxSqDist = 0 let index: number const fp = points[first] const lp = points[last] for (let i = first + 1; i < last; i++) { const p = points[i] const sqDist = GetSqSegDist(p, fp, lp) if (sqDist > maxSqDist) { index = i maxSqDist = sqDist } } if (maxSqDist > sqTolerance) { if (index - first > 1) SimplifyDPStep(points, first, index, sqTolerance, simplified, offset) simplified.push(points[index]) if (last - index > 1) SimplifyDPStep(points, index, last, sqTolerance, simplified, offset) } else { // 记录偏移 const v = new Vector2(lp.x - fp.x, lp.y - fp.y).normalize() for (let i = first + 1; i < last; i++) { const p = points[i] const offsetDist = -CrossVector2(v, { x: p.x - fp.x, y: p.y - fp.y }) offset.positiveOffset = Math.max(offset.positiveOffset, offsetDist) offset.negativeOffset = Math.min(offset.negativeOffset, offsetDist) } } } // Ramer-Douglas-Peucker 算法 export function SimplifyDouglasPeucker(points: P[], sqTolerance: number): [P[], IOffset] { const last = points.length - 1 const simplified: P[] = [points[0]] const offset: IOffset = { negativeOffset: 0, positiveOffset: 0 } SimplifyDPStep(points, 0, last, sqTolerance, simplified, offset) simplified.push(points[last]) return [simplified, offset] }