纯客户端的地图量算

 通常地图量算指的是距离量算和面积量算。git

 在线的各种地图也都提供了纯客户端的地图量算——不须要和服务器交互,技术上用三角函数就能够,虽然本文也讨论这个话题,可是会比较下适用于不一样状况的量算。github

 简单事情简单作:直接计算地图坐标系的距离和面积。贴OpenLayers的代码。算法

 线段距离量算:服务器

    getLength: function() {

 

        var length = 0.0;
        if ( this.components && (this.components.length > 1)) {
            for(var i=1, len=this.components.length; i<len; i++) {
                length += this.components[i-1].distanceTo(this.components[i]);
            }
        }
        return length;
    }

 经过节点间的距离和,获得距离长度,而两点间的距离计算,a2+b2=c2的三角函数再熟悉不过了。函数

 多边形面积量算:ui

    getArea: function() {
        var area = 0.0;
        if ( this.components && (this.components.length > 2)) {
            var sum = 0.0;
            for (var i=0, len=this.components.length; i<len - 1; i++) {
                var b = this.components[i];
                var c = this.components[i+1];
                sum += (b.x + c.x) * (c.y - b.y);
            }
            area = - sum / 2.0;
        }
        return area;
    }

 有了以上的公式,就能完成基本的客户端量算功能了。 this

 如今出现了一个问题,这种基于地图的量算准确吗?碰到了经纬度地图的话结果难道是度为单位?spa

 因为地图是通过地图投影以后显示到二维坐标系上的,因此地图上两点之间的直线映射到地球球面以后,可能就不是两点之间的最短距离了(固然若是地图自己是等角投影就没问题了,这里就再也不深刻讨论有关投影的知识了),偏差产生了。这个偏差对科学研究很重要,但对于咱们平常生活来讲,可能并不重要,为何呢?一般咱们的测距、测面积都是在城市级别,甚至只是在街道级别,那么这相对投影所带来的地图变形来讲,微不足道,所以若是是这方面的应用,那么以上的测距和测面积的算法足够用了。可是,若是非要更加精确的计算结果该如何办?下面就讲讲在客户端实现近似精确的计算方法:component

 测地距离,摘自OpenLayers:orm

      getGeodesicLength: function(projection) {
        var geom = this;  // so we can work with a clone if needed
        if(projection) {
            var gg = new OpenLayers.Projection("EPSG:4326");
            if(!gg.equals(projection)) {
                geom = this.clone().transform(projection, gg);
            }
        }
        var length = 0.0;
        if(geom.components && (geom.components.length > 1)) {
            var p1, p2;
            for(var i=1, len=geom.components.length; i<len; i++) {
                p1 = geom.components[i-1];
                p2 = geom.components[i];
                // this returns km and requires lon/lat properties
                length += OpenLayers.Util.distVincenty(
                    {lon: p1.x, lat: p1.y}, {lon: p2.x, lat: p2.y}
                );
            }
        }
        // convert to m
        return length * 1000;
    }

 考虑到投影的问题,首先要对目标几何对象作投影转换,转换为EPSG:4326,而后基于该大地参考系,计算两点间的球面距离,相比于非测地距离量算,这里的重点是在一个特定的大地参考系下计算两点或多点的球面距离,所以结果也更加精确。

 测地面积,摘自OpenLayers:

    getGeodesicArea: function(projection) {

 

        var ring = this;  // so we can work with a clone if needed
        if(projection) {
            var gg = new OpenLayers.Projection("EPSG:4326");
            if(!gg.equals(projection)) {
                ring = this.clone().transform(projection, gg);
            }
        }
        var area = 0.0;
        var len = ring.components && ring.components.length;
        if(len > 2) {
            var p1, p2;
            for(var i=0; i<len-1; i++) {
                p1 = ring.components[i];
                p2 = ring.components[i+1];
                area += OpenLayers.Util.rad(p2.x - p1.x) *
                        (2 + Math.sin(OpenLayers.Util.rad(p1.y)) +
                        Math.sin(OpenLayers.Util.rad(p2.y)));
            }
            area = area * 6378137.0 * 6378137.0 / 2.0;
        }
        return area;
    }

 一样的,首先对目标几何对象作投影转换,转成咱们所熟知的EPSG:4326,而后再计算球面面积。球面面积计算也不一样于平面多边形的面积计算,须要立体几何的知识了,呵呵。

 通常,这种计算更适合在经纬度地图中使用,普通的米制投影地图可使用简单的方法,城市级的量算偏差基本能够忽略。固然,也不能排除对距离和面积特别敏感的案例,以前也接触过一些在通讯领域的案例,最终使用了后面这种测地算法。

 

 最后,说说在iClient中如何用的问题。

 iClient自身是带了服务器的量算功能的,而若是但愿使用客户端量算的话,iClient for JavaScript已经在Geometry的公共接口中提供了,可自行查找;而iClient for Flex没有提供相似的功能,那么最好借助openscales-geometry库中所带的方法——getLength/getGeodesicLength/getArea/getGeodesicArea得到帮助。为了简化openscales和iClient for Flex之间的几何对象转换关系,能够用https://github.com/SuperMap/OpenScales-FeatureTransform 项目提供的方法来处理。

相关文章
相关标签/搜索