过滤多边形中冗余的点
大家好,我是前端丁修。
在图形学和前端开发中,处理多边形时,顶点通常以循环的方式连接,即第一个点与最后一个点相连。有时需要优化多边形的点,移除路径中不必要的点以简化多边形结构。本节将介绍如何使用 TypeScript 实现一个过滤多边形中冗余点的工具。
功能列表
-
初始化多边形
定义多边形的点集。 -
检测和移除冗余点
判断哪些点是多余的,并将其移除。 -
优化后的多边形输出
输出经过优化后的点集。
实现过滤冗余点的方法
我们将采用共线检测和距离阈值的方法来判断点是否冗余。通过检查连续三个点是否共线,可以有效识别并删除那些位于直线上的中间点,从而优化多边形的顶点数,提升计算效率。
共线检测
如果三个连续的点在同一直线上,中间的点就是冗余的,可以被移除。
距离阈值
在某些情况下,点之间的距离过小也可以被认为是冗余的,根据设定的阈值来移除这些点。
代码实现
下面是过滤多边形中冗余点的 TypeScript 实现。
// 定义点的接口
interface Point {
x: number;
y: number;
}
// 多边形的类
class Polygon {
points: Point[];
constructor(points: Point[]) {
this.points = points;
}
// 检查三个点是否共线
private isCollinear(p1: Point, p2: Point, p3: Point): boolean {
const area =
p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y);
return Math.abs(area) < 1e-6; // 容差
}
// 计算两点之间的距离
private distance(p1: Point, p2: Point): number {
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
}
// 移除近距离的点
private removeClosePoints(distanceThreshold: number): void {
if (this.points.length <= 3) return;
// 先检查首尾点
if (
this.distance(this.points[0], this.points[this.points.length - 1]) <=
distanceThreshold
) {
this.points.pop();
}
this.points = this.points.filter((point, index, arr) => {
if (index === 0) return true;
return this.distance(point, arr[index - 1]) > distanceThreshold;
});
}
// 移除共线的点
private removeCollinearPoints(): void {
if (this.points.length <= 3) return;
const filteredPoints: Point[] = [];
const n = this.points.length;
for (let i = 0; i < n; i++) {
// 保证 i 为 0 时,i - 1 不会变为负数
const prev = this.points[(i - 1 + n) % n];
const current = this.points[i];
// 取模运算,用于确保索引始终在 0 到 n-1 之间,避免数组越界
const next = this.points[(i + 1) % n];
if (
this.isCollinear(prev, current, next) &&
// 检查当前点之后是否至少还有两个点。
// 如果 i + 2 大于或等于 n,意味着已经到达数组的末尾,此时不需要进一步检查共线性,直接保留当前点。
(i + 2 >= n ||
!this.isCollinear(current, next, this.points[(i + 2) % n]))
) {
continue;
}
filteredPoints.push(current);
}
this.points = filteredPoints;
}
// 过滤冗余点
private filterRedundantPoints(distanceThreshold: number = 0.01): void {
if (this.points.length < 3) return;
this.removeClosePoints(distanceThreshold);
this.removeCollinearPoints();
}
// 输出多边形的点
getPoints(): Point[] {
return this.points;
}
}
使用方法
创建一个 Polygon
实例,传入点集后调用 filterRedundantPoints
方法即可过滤冗余点。通过调整 distanceThreshold
参数,可以控制距离过滤的敏感度。
const polygon = new Polygon([
{ x: 100, y: 100 },
{ x: 200, y: 100 },
{ x: 200.02, y: 100 }, // 距离过近的点
{ x: 300, y: 100 }, // 共线点
{ x: 400, y: 100 },
{ x: 400, y: 200 },
{ x: 400.01, y: 200.01 }, // 距离过近的点
{ x: 300, y: 300 },
{ x: 200, y: 300 },
{ x: 100, y: 300 },
{ x: 100, y: 200 }, // 回到起点
]);
polygon.filterRedundantPoints(0.05);
console.log("优化后点集:", polygon.getPoints());
说明:
蓝色点:保留的点 红色点:因距离过近被移除的点 橙色点:因共线被移除的点 实线:过滤后的多边形 输出:
优化后点集: [
{
"x": 100,
"y": 100
},
{
"x": 200,
"y": 100
},
{
"x": 400,
"y": 100
},
{
"x": 400,
"y": 200
},
{
"x": 300,
"y": 300
},
{
"x": 100,
"y": 300
}
]