openlayer的凸包算法实现

最近在要实现一个openlayer的凸多边形,也遇到了不小的坑,就记录一下

1.具体的需求:

  通过在界面点击,获取点击是的坐标点,来绘制一个凸多边形。

2.思考过程:

  1)首先,我们得先获取点击事件发生时,触发的点的坐标

    

map.events.register(‘click‘, map, function (e) {
    var pixel = new OpenLayers.Pixel(e.xy.x,e.xy.y);
    var lonlat = map.getLonLatFromPixel(pixel);
    /*  lonlat.transform(new OpenLayers.Projection("EPSG:4326")); //由900913坐标系转为4326 */
    var newPoint = new OpenLayers.Geometry.Point(lonlat.lon,lonlat.lat);
})

  2)将获得的点做成一个凸多边形(ps:中间遇到点小坑)

    (1)将获得的点坐标设置为map的点对象,点对象一步步转化为一个map的多边形对象

     

    /**
        * 绘画凸多边形图层
        * @param {Object} pointList
        */
       function drawConvex(pointList){
        var linearRing = new OpenLayers.Geometry.LinearRing(pointList);
        var LinearArr = linearRing.components;
        var polygonFeature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([linearRing]));
         map.addLayer(vectorLayer);
         vectorLayer.addFeatures([polygonFeature]);
       }  

  接下来,重要的来了,如何将获取的无序的坐标集合转化为凸多边形的点呢?(这里也是血泪史的开始)

  原本的思路:1.首先得到点,前两个点不做判断,

  ·      2.将第三个开始的坐标做一个判断,判断是否在凸多边形内

      //判断点是否在多边形内
            function PointInPoly(pt, poly) {
                for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
                    ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y))
                    && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x)
                    && (c = !c);
                return c;
            }

      3将不在凸多边形内的点(也就是新点)与多边形的其他坐标做判断,通过距离排序来找出距离最近的点,然后将新点插入点的数组中,本以为这样就可以得到一个有            序的点数组,结果代码写出来了,发现这个和预想不一样,未获得预想的效果。具体代码如下,有大牛懂的话可以指点下。

  

    //确定插入点在多边形的位置
    function idIndex(p, points){
        var arr = [];
        for(var i =0;i<points.length;i++){
            var obj ={"id":"","distance":"","name":""};
            obj.distance = getFlatternDistance(points[i],p);
            obj.id=i;
            obj.name = points[i].id;
            arr.push(obj);
        }
        arr.sort(by("distance"));
        console.log("arr距离:",arr);
        if(arr.length<2)
            return 0;

        return arr[1].id;
    }

    /**
     * by函数接受一个成员名字符串做为参数
     并返回一个可以用来对包含该成员的对象数组进行排序的比较函数
     * @param {Object} name
     */
    function by(name){
        return function(o,p){
            var a, b;
            if(typeof o === "object" && typeof p === "object" && o && p) {
                a= o[name];
                b= p[name];
                if(a === b) {
                    return 0;
                }
                if(typeof a === typeof b) {
                    return a < b ? -1 : 1;
               }
                return typeof a < typeof b ? -1 : 1;
          }else{
            throw("error");
           }
      }
    }

    //俩点之间的距离
    function getFlatternDistance(pointa,pointb){
        var f = getRad((pointa.x + pointb.x)/2);
        var g = getRad((pointa.x - pointb.x)/2);
        var l = getRad((pointa.y - pointb.y)/2);               

        var sg = Math.sin(g);
        var sl = Math.sin(l);
        var sf = Math.sin(f);            

        var s,c,w,r,d,h1,h2;
        var a = EARTH_RADIUS;
        var fl = 1/298.257;

        sg = sg*sg;
        sl = sl*sl;
        sf = sf*sf;

        s = sg*(1-sl) + (1-sf)*sl;
        c = (1-sg)*(1-sl) + sf*sl;

        w = Math.atan(Math.sqrt(s/c));
        r = Math.sqrt(s*c)/w;
        d = 2*w*a;
        h1 = (3*r -1)/2/c;
        h2 = (3*r +1)/2/s;

        return d*(1 + fl*(h1*sf*(1-sg) - h2*(1-sf)*sg));
    }

    var EARTH_RADIUS = 6378137.0;    //单位M
    var PI = Math.PI;
    function getRad(d){
         return d*PI/180.0;
    }

  最后,是实现凸包算法的代码(下面的代码是git上找到的,可以实现给一个无序数组,将其中的点排序,过滤生成一个凸多边形,可以省略掉我上面判断点是否在多边形内)

     function convexHull(points) {
            points.sort(function (a, b) {
                return a.x != b.x ? a.x - b.x : a.y - b.y;
            });

            var n = points.length;
            var hull = [];

            for (var i = 0; i < 2 * n; i++) {
                var j = i < n ? i : 2 * n - 1 - i;
                while (hull.length >= 2 && removeMiddle(hull[hull.length - 2], hull[hull.length - 1], points[j]))
                    hull.pop();
                hull.push(points[j]);
            }

            hull.pop();
            return hull;
        }

        function removeMiddle(a, b, c) {
            var cross = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
            var dot = (a.x - b.x) * (c.x - b.x) + (a.y - b.y) * (c.y - b.y);
            return cross < 0 || cross == 0 && dot <= 0;
        }  

最后,出一张效果图

 

时间: 2024-11-08 20:21:34

openlayer的凸包算法实现的相关文章

计算几何-凸包算法 Python实现与Matlab动画演示

凸包算法是计算几何中的最经典问题之一了.给定一个点集,计算其凸包.凸包是什么就不罗嗦了 本文给出了<计算几何——算法与应用>中一书所列凸包算法的Python实现和Matlab实现,并给出了一个Matlab动画演示程序. 啊,实现谁都会实现啦╮(╯▽╰)╭,但是演示就不一定那么好做了. 算法CONVEXHULL(P)  输入:平面点集P  输出:由CH(P)的所有顶点沿顺时针方向组成的一个列表 1.   根据x-坐标,对所有点进行排序,得到序列p1, …, pn 2.   在Lupper中加入p

Graham Scan凸包算法

获得凸包的算法可以算是计算几何中最基础的算法之一了.寻找凸包的算法有很多种,Graham Scan算法是一种十分简单高效的二维凸包算法,能够在O(nlogn)的时间内找到凸包. 首先介绍一下二维向量的叉积(这里和真正的叉积还是不同的):对于二维向量a=(x1,y2)和b=(x2,y2),a×b定义为x1*y2-y1*x2.而它的几何意义就是|a||b|sin<a,b>.如果a与b夹角小于180度(逆时针),那么这个值就是正值,大于180度就是负值.需要注意的是,左乘和右乘是不同的.如图所示:

线段余弦角+凸包算法

/// /// 根据余弦定理求两个线段夹角 /// /// 端点 /// start点 /// end点 /// double Angle(PointF o, PointF s, PointF e) { double cosfi = 0, fi = 0, norm = 0; double dsx = s.X - o.X; double dsy = s.Y - o.Y; double dex = e.X - o.X; double dey = e.Y - o.Y; cosfi = dsx * de

凸包算法

先理解下凸包 说凸包首先要说凸性的定义,简单点说就是平面邻域中任意两点所在的线段上的点都在该邻域中,则该邻域具有凸性.简单推敲一下,就可以发现如果邻域中存在一阶导数不连续的点一定无法被某点集线性表示出来.再往下的内容属于数学分析了,对我们的算法设计帮助不大,暂时先不管. 一般的计算几何问题都是处理的离散点集形成的平面域,所以我们感兴趣的是怎样找一个包含这个点集的面积最小的凸多边形,这就是凸包.作为常识也应该知道凸包上的顶点必然是该点集的子集,所以根据此性质我们就可以设计高效算法. 下面将介绍三种

平面上圆的凸包算法

平面上圆的凸包算法 我们之前探讨过这个有趣的问题: 平面上有若干圆,求包含这些圆的所有凸集的交. 根据之前讨论的结果,直接按圆心排序做扫描线的方法是错误的.我们需要考虑圆上的每一个点是否可以作为凸包上的一部分. 然而圆上的点的数目是无限多的.我们需要借助离散化的思想:因为我们发现凸包一定是由若干圆弧和线段构成的.而其中线段一定是切线段.由此,我们只需要将每两两圆的切点取出来求一个凸包.显然,在圆凸包上出现的切线段一定会在切点凸包中出现:而切点凸包中其余的线段则一定是弧弦. 但是,这个算法需要枚举

凸包算法的应用——数一数图形中共有多少三角形

一.问题引入 网络上经常会遇到判断图形个数的题目,如下例: 如果我们要把图中所有三角形一个一个选出来,在已知每个交点的前提下,该如何用代码判断我们选的图形是否是三角形呢.如下图,如何把图3筛选出来呢? 这里需要用到两步: 1.得到所选图形(阴影部分)所包含的所有小图形的顶点集合,求集合的凸包,根据凸包顶点个数判定凸包围成的图形是否是三角形,若顶点个数不为3则不是三角形,如图(1). .2.若凸包围成的图形是三角形,判断凸包的面积与所选图形(所有选中的小图形面积之和)是否相等,若相等则所选图形是三

opengl:凸包算法

准备工作 判断点在有向线段的左侧 可以通过叉积判断,如下为k在有向线段ab的左侧代码描述: double multiply(Point a, Point b, Point k) { double x1 = b.x-a.x; double y1 = b.y-a.y; double x2 = k.x-a.x; double y2 = k.y-a.y; return x1*y2-x2*y1; } bool toLeft(Point a, Point b, Point k) { return multi

凸包算法-GrahamScan+暴力+分治

RT.求平面上点集的凸包. 1. GrahamScan算法,<算法导论>上的例子,先找到y最小的点O,以O建立极坐标,其它点按极角排序后再从头开始扫描(配合stack实现). 2.BruteForce算法,依赖定理:如果一个点在平面上某三个点组成的三角形内,那么这个点不可能是凸包上的点. 所以暴力的思路是平面上的点每4个进行枚举,并判断是否满足定理,若满足,则删除这个点继续找:一直找到没有满足定理的点为止.. 3.DivideAndConquer思路:有很多种,这里我实现的只是严格意义上最后一

587. Erect the Fence(凸包算法)

问题 给定一群树的坐标点,画个围栏把所有树围起来(凸包). 至少有一棵树,输入和输出没有顺序. Input: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]] Output: [[1,1],[2,0],[4,2],[3,3],[2,4]] 思路和代码 1. 暴力法(超时) 对于任意两点连成的一条直线,如果其它所有点都在这条直线的一侧,则这两个点为解集中的两个点. 怎么判断点在直线的同一侧呢? 假设确定直线的两点为p1(x1, y1)和p2(x2, y2),方向从p1到p