c#
csharp
复制代码
```csharp
/// <summary>
/// 使用 Douglas-Peucker 算法简化点集合
/// </summary>
/// <param name="points">原始点集</param>
/// <param name="tolerance">简化阈值(距离),建议 0.01 ~ 0.5 mm</param>
/// <returns>简化后的点集</returns>
public static List<TopoPoint> Simplify(
List<TopoPoint> points,
double tolerance)
{
if (points == null || points.Count <= 2)
return points; // 少于3个点无需简化
var keep = new bool[points.Count];
for (int i = 0; i < keep.Length; i++) keep[i] = false;
keep[0] = true;
keep[points.Count - 1] = true;
SimplifyRec(points, 0, points.Count - 1, tolerance, keep);
return points.Where((pt, index) => keep[index]).ToList();
}
private static void SimplifyRec(
List<TopoPoint> points,
int start,
int end,
double tolerance,
bool[] keep)
{
if (start + 1 >= end) return;
// 找到距离起点-终点线段最远的点
double maxDist = 0;
int maxIndex = start;
for (int i = start + 1; i < end; i++)
{
double dist = PerpendicularDistance(
points[start].X, points[start].Y,
points[end].X, points[end].Y,
points[i].X, points[i].Y);
if (dist > maxDist)
{
maxDist = dist;
maxIndex = i;
}
}
if (maxDist > tolerance)
{
keep[maxIndex] = true;
SimplifyRec(points, start, maxIndex, tolerance, keep);
SimplifyRec(points, maxIndex, end, tolerance, keep);
}
}
/// <summary>
/// 点到线段的垂直距离
/// </summary>
private static double PerpendicularDistance(
double ax, double ay,
double bx, double by,
double px, double py)
{
double dx = bx - ax;
double dy = by - ay;
if (dx == 0 && dy == 0)
return Math.Sqrt((px - ax) * (px - ax) + (py - ay) * (py - ay));
// 距离公式:| (dy*px - dx*py + bx*ay - by*ax) | / sqrt(dx² + dy²)
double numerator = Math.Abs(dy * px - dx * py + bx * ay - by * ax);
double denominator = Math.Sqrt(dx * dx + dy * dy);
return numerator / denominator;
}
}
复制代码
### c++
```csharp
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
// 定义点类型
using Point = std::pair<double, double>;
using PointList = std::vector<Point>;
/**
* 计算点 p 到线段 (start -> end) 的垂直距离
*/
double PerpendicularDistance(
const Point& start,
const Point& end,
const Point& p)
{
double dx = end.first - start.first;
double dy = end.second - start.second;
// 如果线段退化为点
if (std::abs(dx) < 1e-10 && std::abs(dy) < 1e-10)
{
double dx1 = p.first - start.first;
double dy1 = p.second - start.second;
return std::sqrt(dx1 * dx1 + dy1 * dy1);
}
// 距离公式:| (dy * px - dx * py + end.x * start.y - end.y * start.x) | / sqrt(dx² + dy²)
double numerator = std::abs(dy * p.first - dx * p.second + end.first * start.second - end.second * start.first);
double denominator = std::sqrt(dx * dx + dy * dy);
return numerator / denominator;
}
/**
* Douglas-Peucker 递归处理
*/
void DouglasPeuckerRecursive(
const PointList& points,
int startIdx,
int endIdx,
double tolerance,
std::vector<bool>& keep)
{
if (startIdx + 1 >= endIdx)
return;
// 找出距离线段最远的点
double maxDistance = 0.0;
int maxIndex = startIdx;
for (int i = startIdx + 1; i < endIdx; ++i)
{
double dist = PerpendicularDistance(points[startIdx], points[endIdx], points[i]);
if (dist > maxDistance)
{
maxDistance = dist;
maxIndex = i;
}
}
// 如果最远距离大于阈值,则保留该点并递归处理两侧
if (maxDistance > tolerance)
{
keep[maxIndex] = true;
DouglasPeuckerRecursive(points, startIdx, maxIndex, tolerance, keep);
DouglasPeuckerRecursive(points, maxIndex, endIdx, tolerance, keep);
}
}
/**
* 简化点集合:Douglas-Peucker 算法主函数
* @param points 原始点集(至少2个点)
* @param tolerance 简化阈值(单位:mm 或脉冲),建议 0.01 ~ 0.5
* @return 简化后的点集
*/
PointList SimplifyPoints(const PointList& points, double tolerance)
{
int n = points.size();
if (n <= 2)
return points; // 无需简化
std::vector<bool> keep(n, false);
keep[0] = true;
keep[n - 1] = true;
DouglasPeuckerRecursive(points, 0, n - 1, tolerance, keep);
PointList result;
for (int i = 0; i < n; ++i)
{
if (keep[i])
{
result.emplace_back(points[i]);
}
}
return result;
}