首先,将一条曲线首、末点连一条直线,求出其余各点到该直线的距离,选取其最大者与规定的临界值相比较,若大于临界值,则离该支线距离最大的点保留,否则将直线两端点间个点全部舍去,即道格拉斯-普克(Douglas-Peucker)法。
该算法是矢量数据压缩最常用的方法之一,可以很好地保留折线的变化趋势。
MFC实现过程如下:
struct PNT
{
int x;
int y;
}; //保存点数据的结构
PNT arr[100]; //用于保存原始点
PNT arr2[100]; //保存压索后的点
int p; //arr的指针
int p2; //arr2的指针
typedef PNT VEC; //保存向量的数据,用于计算距离
void CDPDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
//鼠标左键点击事件
//当在屏幕上点击鼠标左键时,显示出点击位置以及绘制连线,并将该位置坐标存入数组arr中
CDC* pDC = GetDC();//创建画笔
pDC->Ellipse(point.x - 5, point.y - 5, point.x + 5, point.y + 5);//在点击位置画一个小圆显示。
arr[p].x = point.x;
arr[p].y = point.y;//坐标点存入arr
//从第二个点开始,绘制连线
if (p > 0)
{
pDC->MoveTo(arr[p - 1].x, arr[p - 1].y);
pDC->LineTo(arr[p].x, arr[p].y);
}
p++;
CDialogEx::OnLButtonDown(nFlags, point);
}
void CDPDlg::OnBnClickedButton1()
{
//按下btn按钮后的事件
UpdateData(); //更新文本框数据
//创建画笔,更改颜色以便和原来的线区分开
CDC* pDC = GetDC();
CPen pen;
pen.CreatePen(0, 5, RGB(255, 0, 0));
pDC->SelectObject(&pen);
PNT temparr[100]; //用于保存压缩后的点数据,该数组还需再次经过处理
for (int i = 0; i < 100; i++)
{
temparr[i].x = -1;
temparr[i].y = -1;
}
//调用DP递归方法
//参数分别代表:左端点、右端点、阈值、原始数据数组、处理后的数据数组
DP(0, p - 1, Threshold, arr, temparr);
//删去temparr中的空白数据
for (int i = 0; i < 100; i++)
{
if (temparr[i].x != -1)
{
arr2[p2].x = temparr[i].x;
arr2[p2++].y = temparr[i].y;
}
}
//绘制压缩后的线段
for (int i = 1; i < p2; i++)
{
pDC->MoveTo(arr2[i- 1].x, arr2[i - 1].y);
pDC->LineTo(arr2[i].x, arr2[i].y);
}
}
void CDPDlg::DP(int left, int right, int value, const PNT* arr1, PNT* arr2)
{
// 算法的递归实现
if (left > right)
return;
arr2[left] = arr1[left];
arr2[right] = arr1[right];
double dis; //左右端点连线到其余点的距离
double maxdis=0; //左右端点连线到其余点的距离最大值
int maxpos; //左右端点连线到其余点的距离最大值索引
VEC v1;
VEC v2; //两个向量用于计算距离
v1.x = arr[right].x - arr[left].x;
v1.y = arr[right].y - arr[left].y;
double cosa, sina;
for (int i = left; i <= right; i++)
{
v2.x = arr[i].x - arr[left].x;
v2.y = arr[i].y - arr[left].y;
cosa = (v1.x * v2.x + v1.y * v2.y) / (sqrt(v1.x * v1.x + v1.y * v1.y) * sqrt(v2.x * v2.x + v2.y * v2.y));
sina = sqrt(1 - cosa * cosa);
dis = sqrt(v2.x * v2.x + v2.y * v2.y) * sina;
if (dis > maxdis)
{
maxdis = dis;
maxpos = i;
}
}
if (maxdis > value)
{
arr2[maxpos] = arr1[maxpos];
DP(left, maxpos, value, arr1, arr2);
DP(maxpos, right, value, arr1, arr2);
}
else
{
return;
}
}
效果展示如下: