zoukankan      html  css  js  c++  java
  • 道格拉斯-普克算法(JavaScript实现)

    需求:

    有时候当移动速度很慢,GPS定位的轨迹点就非常的多,这时候为了缩减数据量,需要将不突出的点去掉。

    思路:

      (1) 在曲线首尾两点间虚连一条直线,求出其余各点到该直线的距离。

    (2)选其最大者与阈值相比较,若大于阈值,则离该直线距离最大的点保留,否则将直线两端点间各点全部舍去。
    (3)依据所保留的点,将已知曲线分成两部分处理,重复第1、2步操作,迭代操作,即仍选距离最大者与阈值比较,依次取舍,直到无点可舍去,最后得到满足给定精度限差的曲线点坐标

    这里使用道格拉斯-普克算法实现,易于理解。效果对比图如下:

    源代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
       <title>DouglasPeucker</title>    
    </head>
    <body>
       <canvas id="drawing" style="height:300px;100%"></canvas>
        <canvas id="drawing2" style="height:300px;100%"></canvas>
    </body>
    <script type="text/javascript" >
    
        var points1=[];
        var pointsshao=[];
        var pts=[]; 
        var hval=30;//阈
        
        //随机生成1000个点
        for(var i=0;i<1000;i++){
        var  oldx=i*10,oldy=Math.random()*150;
          points1.push([oldx,oldy,i]);
        }
        
        //求斜率
        function xielv(pt1,pt2)
        {
          var k,b;
          var canshu={};
          canshu.k=(pt1[1]-pt2[1])/(pt1[0]-pt2[0]);
          canshu.b=pt1[1]-canshu.k*pt1[0];
          return canshu;
        }
        //求点到直线的距离
        function distanceToline(pt,cs){
           return (Math.abs(cs.k*pt[0]-pt[1]+cs.b))/Math.sqrt(cs.k*cs.k+1);
        }
        
        //开始计算(道格拉斯普克算法)
        pts.push(points1[0]);
        countPoint(points1);
        pts.push(points1[points1.length-1]);
    
        //排序
        function sort(pts){
          for(var i=0;i<pts.length-1;i++)
          {
             var a=pts[i];
             var b=pts[i+1];
             if(b[2]>a[2]){
             pts[i]=b;
             pts[i+1]=a;
             for(var j=i;j>0;j--)
             {
                 var c=pts[j-1];
                 if(b[2]>c[2]){
                   pts[j-1]=b;
                   pts[j]=c;
                 }
             }
             }
          }
        }
      //对坐标点进行取舍
     function countPoint(points){
     
           var maxD=0;
           var maxPoint=null;
           var maxindex=0;
           //大于2个点才开始计算
           if(points.length>2){
                 var pt1=points[0];
               var pt2=points[points.length-1];
               var cs=xielv(pt1,pt2);
               for(var i=0;i<points.length;i++){
                 var pt=points[i];
                 var dis=distanceToline(pt,cs);
                //判断该线段中是否有点到由该线段端点组成的直线的距离大于限值
                 if(dis>maxD)
                 {
                   maxD=dis;
                   maxPoint=pt;
                   maxindex=i;
                 }
               }
                   if(maxD>hval) //如果最大值就从该点位置将线段进行切分
                 {
                     var pts1=points.slice(maxindex);//中分末尾数组
                     var pts2=points.slice(0,maxindex+1);//中分前面数组
                    if(pts1.length>2 && pts2.length>2)
                    {
                     if(!countPoint(pts1) && !countPoint(pts2)){  //如果两个线段都没有超过限制就结束计算
                       pts.push(maxPoint);
                     }
                    }else if(pts1.length>2 && pts2.length<=2){ //计算pts1
                        if(!countPoint(pts1))pts.push(maxPoint);
                        
                    }else if(pts1.length<=2 && pts2.length>2){ //计算pts2
                       if(! countPoint(pts2))pts.push(maxPoint);
                        
                    }
                 } return false;
           }
         }
        //由大到小
        sort(pts);
        drawWay("drawing2",pts);
        drawWay("drawing",points1)
    //绘制曲线
    function drawWay(name,points){ var drawing=document.getElementById(name); if(drawing.getContext){ var context=drawing.getContext("2d"); context.beginPath(); var oldx=points[0][0]; var oldy=points[0][1]; for(var i=0;i<points.length;i++){ var p=points[i]; context.moveTo(oldx,oldy); oldx=p[0]; oldy=p[1]; context.lineTo(oldx,oldy); } context.closePath(); context.stroke(); } } </script>
  • 相关阅读:
    NIO简述
    函数式编程
    ReadWriterLock读写锁
    Semaphore工具类使用
    CyclicBarrier工具类使用
    CountDownLatch工具类使用
    创建VUE+Element-UI项目
    <slot>插板使用
    Spring面试题
    实现定时任务的几种方式
  • 原文地址:https://www.cnblogs.com/GIScore/p/9840454.html
Copyright © 2011-2022 走看看