Files
cut-abstractions/samples/handleAbility/common/LayoutEngine/Simplify2.ts

86 lines
2.2 KiB
TypeScript

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]
}