zoukankan      html  css  js  c++  java
  • 通过坐标系求覆盖物面积

    首先先供上原文链接:https://blog.csdn.net/neil89/article/details/49331641

    这是我在项目上遇到的问题,在地图上标注多边形覆盖物,同时求出覆盖物的面积。在查找方法的过程中,首先了解了百度api中的通过坐标获取面积的方式,解读代码发现求解方式是依照地球是曲面的这个标准计算的面积,当我将api中的就是方法拷贝出来自己封装调用后发现,面积大于2000平方米的区域面积大小计算误差较小,但是当覆盖较小区域时计算的误差特别大,甚至会出现负数的情况。针对这一概念,我进行了深度思考,结合百度参考发现,有可能是在曲面计算过程中向量的方向错误导致数据有误,还有可能曲率问题导致较小面积的数据不准确问题。通过进一步的思考,我想较小的面积可以看做是近似于平面多边形的方式计算(这就可以做两个方法,分别是大面积和小面积的不同求解方法),沿着这样的思路,回忆起可以将多边形分成多个三角形然后分别通过海伦公式(坐标间距离可以求出)求出三角形面积并求和得到多边形的面积。(这一多边形依然不包括有交叉边界的多边形)(这只是我个人的想法,实践起来可能要花一些时间,下面是百度到的一篇一样分为两种面积求法的代码)

    【网站上的算法比较复杂,我还没有钻研过深,如果有理解的可以反馈大致思路】

    下面是大神代码原文供大家欣赏:

    var earthRadiusMeters = 6371000.0;
    var metersPerDegree = 2.0 * Math.PI * earthRadiusMeters / 360.0;
    var radiansPerDegree = Math.PI / 180.0;
    var degreesPerRadian = 180.0 / Math.PI;
    var pointArr;

    $(document).ready(function() {
    pointArr = new Array();
    b();
    });

    function calculateArea(points) {
    if (points.length > 2) {
    var areaMeters2 = PlanarPolygonAreaMeters2(points);
    if (areaMeters2 > 1000000.0) {
    areaMeters2 = SphericalPolygonAreaMeters2(points);
    alert("面积为" + areaMeters2 + "平方米");
    }
    }
    }

    /球面多边形面积计算/
    function SphericalPolygonAreaMeters2(points) {
    var totalAngle = 0;
    for (var i = 0; i < points.length; i++) {
    var j = (i + 1) % points.length;
    var k = (i + 2) % points.length;
    totalAngle += Angle(points[i], points[j], points[k]);
    }
    var planarTotalAngle = (points.length - 2) * 180.0;
    var sphericalExcess = totalAngle - planarTotalAngle;
    if (sphericalExcess > 420.0) {
    totalAngle = points.length * 360.0 - totalAngle;
    sphericalExcess = totalAngle - planarTotalAngle;
    } else if (sphericalExcess > 300.0 && sphericalExcess < 420.0) {
    sphericalExcess = Math.abs(360.0 - sphericalExcess);
    }
    return sphericalExcess * radiansPerDegree * earthRadiusMeters * earthRadiusMeters;
    }

    /角度/
    function Angle(p1, p2, p3) {
    var bearing21 = Bearing(p2, p1);
    var bearing23 = Bearing(p2, p3);
    var angle = bearing21 - bearing23;
    if (angle < 0) {
    angle += 360;
    }
    return angle;
    }

    /方向/
    function Bearing(from, to) {
    var lat1 = from[1] * radiansPerDegree;
    var lon1 = from[0] * radiansPerDegree;
    var lat2 = to[1] * radiansPerDegree;
    var lon2 = to[0] * radiansPerDegree;
    var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
    if (angle < 0) {
    angle += Math.PI * 2.0;
    }
    angle = angle * degreesPerRadian;
    return angle;
    }

    /平面多边形面积/
    function PlanarPolygonAreaMeters2(points) {
    var a = 0;
    for (var i = 0; i < points.length; ++i) {
    var j = (i + 1) % points.length;
    var xi = points[i][0] * metersPerDegree * Math.cos(points[i][1] * radiansPerDegree);
    var yi = points[i][1] * metersPerDegree;
    var xj = points[j][0] * metersPerDegree * Math.cos(points[j][1] * radiansPerDegree);
    var yj = points[j][1] * metersPerDegree;
    a += xi * yj - xj * yi;
    }
    return Math.abs(a / 2);
    }

    function b() {
    var s = "112.523197631836,37.868892669677734;112.5170669555664,37.8605842590332;112.52099609375,37.849857330322266;112.54137420654297,37.8512732521875;112.5351180302734,37.858699798583984";
    var s1 = new Array()
    s1 = s.split(";");
    for (var i = 0; i < s1.length; i++) {
    var ss = s1[i];
    var temp = ss.split(",");
    var point = new Array();
    point.push(Number(temp[0]), Number(temp[1]));
    pointArr.push(point);
    }
    calculateArea(pointArr);
    }

    后记:后面会放百度api的相关求面积代码,供大家参考
    //百度api提供方法
    // 检查类型:既不是百度类型的范围又不是数组类型的数据,直接返回0

        //console.log(pts.length);
    
        
         
    
        //如果是百度类型的,得到点集合,不是的话,另说。
        function getArea(polygon) {
        var pts = new Array();
        if (polygon instanceof BMap.Polygon) {
            pts = polygon.getPath();
        }
        if (!(polygon instanceof BMap.Polygon) && !(polygon instanceof Array)) {
           return 0;
        }
    
        ////判断数组的长度,如果是小于3的话,不构成面,无法计算面积
        if (pts.length < 3) {
            return 0;
        }
    
        var totalArea = 0;// 初始化总面积
        var LowX = 0.0;
        var LowY = 0.0;
        var MiddleX = 0.0;
        var MiddleY = 0.0;
        var HighX = 0.0;
        var HighY = 0.0;
        var AM = 0.0;
        var BM = 0.0;
        var CM = 0.0;
        var AL = 0.0;
        var BL = 0.0;
        var CL = 0.0;
        var AH = 0.0;
        var BH = 0.0;
        var CH = 0.0;
        var CoefficientL = 0.0;
        var CoefficientH = 0.0;
        var ALtangent = 0.0;
        var BLtangent = 0.0;
        var CLtangent = 0.0;
        var AHtangent = 0.0;
        var BHtangent = 0.0;
        var CHtangent = 0.0;
        var ANormalLine = 0.0;
        var BNormalLine = 0.0;
        var CNormalLine = 0.0;
        var OrientationValue = 0.0;
        var AngleCos = 0.0;
        var Sum1 = 0.0;
        var Sum2 = 0.0;
        var Count2 = 0;
        var Count1 = 0;
        var Sum = 0.0;
        var Radius = 6378137.0;// ,WGS84椭球半径
        var Count = pts.length;
        for (var i = 0; i < Count; i++) {
            if (i == 0) {
                LowX = pts[Count - 1].lng * Math.PI / 180;
                LowY = pts[Count - 1].lat * Math.PI / 180;
                MiddleX = pts[0].lng * Math.PI / 180;
                MiddleY = pts[0].lat * Math.PI / 180;
                HighX = pts[1].lng * Math.PI / 180;
                HighY = pts[1].lat * Math.PI / 180;
            } else if (i == Count - 1) {
                LowX = pts[Count - 2].lng * Math.PI / 180;
                LowY = pts[Count - 2].lat * Math.PI / 180;
                MiddleX = pts[Count - 1].lng * Math.PI / 180;
                MiddleY = pts[Count - 1].lat * Math.PI / 180;
                HighX = pts[0].lng * Math.PI / 180;
                HighY = pts[0].lat * Math.PI / 180;
            } else {
                LowX = pts[i - 1].lng * Math.PI / 180;
                LowY = pts[i - 1].lat * Math.PI / 180;
                MiddleX = pts[i].lng * Math.PI / 180;
                MiddleY = pts[i].lat * Math.PI / 180;
                HighX = pts[i + 1].lng * Math.PI / 180;
                HighY = pts[i + 1].lat * Math.PI / 180;
            }
            AM = Math.cos(MiddleY) * Math.cos(MiddleX);
            BM = Math.cos(MiddleY) * Math.sin(MiddleX);
            CM = Math.sin(MiddleY);
            AL = Math.cos(LowY) * Math.cos(LowX);
            BL = Math.cos(LowY) * Math.sin(LowX);
            CL = Math.sin(LowY);
            AH = Math.cos(HighY) * Math.cos(HighX);
            BH = Math.cos(HighY) * Math.sin(HighX);
            CH = Math.sin(HighY);
            CoefficientL = (AM * AM + BM * BM + CM * CM) / (AM * AL + BM * BL + CM * CL);
            CoefficientH = (AM * AM + BM * BM + CM * CM) / (AM * AH + BM * BH + CM * CH);
            ALtangent = CoefficientL * AL - AM;
            BLtangent = CoefficientL * BL - BM;
            CLtangent = CoefficientL * CL - CM;
            AHtangent = CoefficientH * AH - AM;
            BHtangent = CoefficientH * BH - BM;
            CHtangent = CoefficientH * CH - CM;
            AngleCos = (AHtangent * ALtangent + BHtangent * BLtangent + CHtangent * CLtangent) / (Math.sqrt(AHtangent * AHtangent + BHtangent * BHtangent + CHtangent * CHtangent) * Math.sqrt(ALtangent * ALtangent + BLtangent * BLtangent + CLtangent * CLtangent));
            AngleCos = Math.acos(AngleCos);
            ANormalLine = BHtangent * CLtangent - CHtangent * BLtangent;
            BNormalLine = 0 - (AHtangent * CLtangent - CHtangent * ALtangent);
            CNormalLine = AHtangent * BLtangent - BHtangent * ALtangent;
            if (AM != 0)
                OrientationValue = ANormalLine / AM;
            else if (BM != 0)
                OrientationValue = BNormalLine / BM;
            else
                OrientationValue = CNormalLine / CM;
            if (OrientationValue > 0) {
                Sum1 += AngleCos;
                Count1++;
            } else {
                Sum2 += AngleCos;
                Count2++;
            }
        }
    
        var tempSum1, tempSum2;
        tempSum1 = Sum1 + (2 * Math.PI * Count2 - Sum2);
        tempSum2 = (2 * Math.PI * Count1 - Sum1) + Sum2;
        if (Sum1 > Sum2) {
            if ((tempSum1 - (Count - 2) * Math.PI) < 1)
                Sum = tempSum1;
            else
                Sum = tempSum2;
        } else {
            if ((tempSum2 - (Count - 2) * Math.PI) < 1)
                Sum = tempSum2;
            else
                Sum = tempSum1;
        }
        totalArea = (Sum - (Count - 2) * Math.PI) * Radius * Radius;
    
        console.log((totalArea.toFixed(4))/10000); // 返回总面积
    
        return totalArea.toFixed(4);
    }
  • 相关阅读:
    为Jupyter只安装目录的扩展包
    前端菜鸟的小程序摸索记录
    小计:Shopee批量删除修复~附脚本
    Python3 与 C# 并发编程之~ 协程篇
    记一次硬件故障,并普及点硬件知识
    小计:协同办公衍生出的需求
    监控MySQL|Redis|MongoDB的执行语句(go-sniffer)
    Linux IO实时监控iostat命令详解
    Linux下的磁盘缓存
    使用top命令查看系统状态
  • 原文地址:https://www.cnblogs.com/hjworld/p/9118636.html
Copyright © 2011-2022 走看看