(GIS算法)矢量数据压缩:道格拉斯-普克算法,MFC

        首先,将一条曲线首、末点连一条直线,求出其余各点到该直线的距离,选取其最大者与规定的临界值相比较,若大于临界值,则离该支线距离最大的点保留,否则将直线两端点间个点全部舍去,即道格拉斯-普克(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;
	}
}

 

效果展示如下:

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值