道格拉斯-普克抽稀算法,是将曲线近似表示为一系列点,并减少点的数量的一种算法。
该算法实现抽稀的过程是:
1)对曲线的首末点虚连一条直线,求曲线上所有点与直线的距离,并找出最大距离值dmax,用dmax与事先给定的阈值D相比:
2)若dmax<D,则将这条曲线上的中间点全部舍去;则该直线段作为曲线的近似,该段曲线处理完毕。
该算法实现抽稀的过程是:
1)对曲线的首末点虚连一条直线,求曲线上所有点与直线的距离,并找出最大距离值dmax,用dmax与事先给定的阈值D相比:
2)若dmax<D,则将这条曲线上的中间点全部舍去;则该直线段作为曲线的近似,该段曲线处理完毕。
若dmax≥D,保留dmax对应的坐标点,并以该点为界,把曲线分为两部分,对这两部分重复使用该方法,即重复1),2)步,直到所有dmax均<D,即完成对曲线的抽稀。
我的思路是利用递归的方法遍历所有的点进行道格拉斯抽稀。
验证数据如图。
其中,黑色的线为原始线状数据,其他颜色为进行抽稀元算时所做辅助线。
准备如下:
ArrayList myar = new ArrayList();//存入原始数据
ArrayList newar = new ArrayList(); //存入抽稀后的数据
public class canshu//记录直线参数的类
{
public double k;
public double b;
}
public class zuobiao//坐标数据类
{
public double x;
public double y;
}
public canshu xielv(zuobiao shou, zuobiao wei)//求斜率
{
double k, b;
canshu newcs = new canshu();
k = (wei.y - shou.y) / (wei.x - shou.x);
b = shou.y - k * shou.x;
newcs.k = k;
newcs.b = b;
return newcs;
}
public double distance(zuobiao dot,canshu cs)//求点到直线距离
{
double dis =(Math.Abs (cs.k * dot.x - dot.y + cs.b)) / Math.Sqrt(cs.k * cs.k + 1);
return dis;
}
道格拉斯算法如下:
public void Douglas(int number1, int number2)
{
int max=0;//定义拥有最大距离值的点的编号
canshu myc = new canshu();
myc= xielv((zuobiao)myar[number1], (zuobiao)myar[number2-1]);
double maxx = distance((zuobiao)myar[number1+1], myc);//假设第二个点为最大距离点
double yuzhi = Convert.ToInt32(textBox1.Text);//设阈值
for (int i = number1 + 1; i < number2 - 1; i++)//从第二个点遍历到最后一个点前方的点
{
if (distance((zuobiao)myar[i], myc) > yuzhi && distance((zuobiao)myar[i], myc) >= maxx)//找出拥有最大距离的点
{
max = i;
maxx = distance((zuobiao)myar[i], myc);
}
}
if(max==0)//若不存在最大距离点,则只将首尾点存入arraylist,结束这一次的道格拉斯抽稀
{
newar.Add((zuobiao)myar[number2-1]);
return;
}
else if (number1 + 1 == max&&number2-2!=max)//如果第二个点是最大距离点,则以下一个点和尾点作为参数进行道格拉斯抽稀释
{
Douglas(max+1, number2);
}
else if (number2 - 2 == max&&number1+1!=max)//<span style="font-family: Arial;">如果倒数第二个点是最大距离点,则以首点和倒数第三点作为参数进行道格拉斯抽稀
</span> {
Douglas(0, max+1);
}
else if (number1 + 1 == max && number2 - 2 == max)//如果首点尾点夹住最大距离点,则将最大距离点和尾点存入arraylist
{
newar.Add((zuobiao)myar[max]);
newar.Add((zuobiao)myar[max+1]);
return;
}
else
{
Douglas(number1, max+1);
Douglas(max, number2);
}
}
不同阈值的运行情况如图: