GIS超级程序猿Geomatics(GIS,GPS,RS,Surveying)

根据高德路径规划出来的轨迹向右平移得到一个闭合范围

2019-05-06  本文已影响3人  邵佳楠

最近遇到一个需求,要求简单点讲就是如何根据高德路径规划出来的道路,然后只取道路右侧的POI兴趣点,比如只取道路右侧的公交站或者是商店。高德有提供查找一个点半径内的兴趣点,但只取右侧的方法确没有,找了一会儿教程,百度谷歌都没有合适的解决方法,没办法只能自己想办法解决。

大致的解决方法分为两步:

  1. 按高德规划的路径向右进行平移形成一个闭合范围、

2.取得需要的POI兴趣点坐标然后判断是否在这个闭合范围内(高德有提供相应的数学计算库)

这里呢主要和大家分享下如何根据高德的路径规划然后向右边平移出一条线路,老样子,废话不多说,直接上代码:


/**
 * 根据已知折线点集计算指定距离的两条平行线的点集
 * @param {MVCArray<LatLng>} 经纬度数组
 * @param {L} 主线和平行线的距离(单位:米)
 */
function setParallelPoints(MVCArray, L) {
    ParallelA = [];
    ParallelB = [];
    var polytemp = [],
        polyArr = [];
    // 取出原线路点集
    for (var i = 0; i < MVCArray.length; i++) {
        polytemp.push(MVCArray[i]);
    }
    // 优化主线点集
    polyArr = initPolyline(polytemp, L);
    // 遍历主线路点集,计算和绘制等距平行线
    for (var i = 1; i < polyArr.length - 1; i++) {
        var lat1, lng1, lat2, lng2;
        var p0 = polyArr[i - 1];
        var p1 = polyArr[i];
        var p2 = polyArr[i + 1];
        var d_latlng1 = getParallelPoint(p0, p1, p2, L / 8);//向左平移一点点(用于我的需求)
        var d_latlng2 = getParallelPoint(p0, p1, p2, L);
        lat1 = p1.lat + d_latlng1.lat;
        lng1 = p1.lng + d_latlng1.lng;
        lat2 = p1.lat - d_latlng2.lat;
        lng2 = p1.lng - d_latlng2.lng;
        ParallelA.push(new AMap.LngLat(lng1, lat1));
        ParallelB.push(new AMap.LngLat(lng2, lat2));
    }
    var result = ParallelA;
    result = result.concat(ParallelB.reverse());
    result.push(ParallelA[0]);
    return result;
}

/**
 * 优化主线点集
 * 折线点集首尾加上辅助点,去掉点间距离过紧的多余点
 * @param {oldArr} 折线点集数组
 * @param {L} 相邻两点间直线距离标准(单位:米)
 * @return newArr 新折线点集数组
 */
function initPolyline(oldArr, L) {
    var newArr = [];
    if (oldArr.length < 2)
        return oldArr;
    // 加入起始辅助点
    newArr.push(new AMap.LngLat(
        oldArr[0].lng * 2 - oldArr[1].lng,
        oldArr[0].lat * 2 - oldArr[1].lat));
    newArr.push(oldArr[0]);
    for (var i = 1; i < oldArr.length - 1; i++) {
        var len = Math.pow(latToLen(oldArr[i].lat - oldArr[i - 1].lat), 2) +
            Math.pow(lngToLen(oldArr[i].lat, (oldArr[i].lng - oldArr[i - 1].lng)), 2);
        if (len > L * L)
            newArr.push(oldArr[i]);
    }
    newArr.push(oldArr[oldArr.length - 1])
    // 加入结尾辅助点
    newArr.push(new AMap.LngLat(
        oldArr[oldArr.length - 1].lng * 2 - oldArr[oldArr.length - 2].lng,
        oldArr[oldArr.length - 1].lat * 2 - oldArr[oldArr.length - 2].lat));
    return newArr;
}

/**
 * 根据已知相邻3点,求中点的等距平行点经纬度
 * 核心算法
 * @param {p0, p1, p2} 相邻三个LatLng点
 * @return {t} 待求平行点到线段的垂直距离
 */
function getParallelPoint(p0, p1, p2, t) {
    // 经纬度分别转换成长度单位
    var y12 = p2.lat - p1.lat;
    var x12 = p2.lng - p1.lng;
    var y01 = p1.lat - p0.lat;
    var x01 = p1.lng - p0.lng;
    if (x12 == 0) {
        a = Math.PI / 2;
        if (y12 < 0)
            a = -a;
    } else {
        a = Math.atan(y12 / x12);
    }
    if (x01 == 0) {
        b = Math.PI / 2;
        if (y01 < 0)
            b = -b;
    } else {
        b = Math.atan(y01 / x01);
    }
    // 关键核心处
    if (p2.lng < p1.lng) {
        a += Math.PI;
    }
    if (p1.lng < p0.lng) {
        b += Math.PI;
    }
    var k = (b - a - Math.PI) / 2;
    var r = a + k;
    var d = t / Math.sin(k);
    var sinr = Math.sin(r);
    var cosr = Math.cos(r);
    var d_lat = lenToLat(d * sinr);
    var d_lng = lenToLng(p1.lat, d * cosr);
    return {
        lat: d_lat,
        lng: d_lng
    };
}

/**
 * 经线方向长度转化成纬度
 * @param {leng} 经线向量长度(米)
 * @return 返回纬度差
 */
function lenToLat(leng) {
    var L = 10002150; // 半个经线长度(经线圈的1/4),对应90°纬度
    var angle = 90 * leng / L;
    return angle;
}
/**
 * 纬线方向长度转化成经度
 * @param {lat} 纬度值 
   * @param {leng} 纬线向量长度(米)
   * @return 返回精度差
 */
function lenToLng(lat, leng) {
    var L = 20037508; // 赤道一半长度(半圈,对应180°经度)
    var latL = L * Math.cos(Math.PI / 180 * lat); // 指定纬度对应的纬线长度(半圈)
    var angle = 180 * leng / latL;
    return angle;
}
/**
 * 纬度差转换成长度
 * @param {d_lat} 纬度差值
 * @return 长度差值
 */
function latToLen(d_lat) {
    var L = 10002150; // 半个经线长度(经线圈的1/4),对应90°纬度
    var len = d_lat * L / 90;
    return len;
}
/**
 * 经度差转换成长度
 * @param {lat} 纬度值 
 * @param {d_lng} 经度差值
 * @return 返回长度差
 */
function lngToLen(lat, d_lng) {
    var L = 20037508; // 赤道一半长度(半圈,对应180°经度)
    var latL = L * Math.cos(Math.PI / 180 * lat); // 指定纬度对应的纬线长度(半圈)
    var len = d_lng * latL / 180;
    return len;
}

高德地图调用示例

map.plugin("AMap.DragRoute", function () {
                route = new AMap.DragRoute(map, path, AMap.DrivingPolicy.LEAST_DISTANCE,
                    {
                        polyOptions: {
                            strokeColor: "#117700", //线颜色
                            showDir: true
                        },
                        showTraffic: false,
                        midMarkerOptions: {
                            visible: false
                        }
                    }); //构造拖拽导航类
                route.search(); //查询导航路径并开启拖拽导航
                route.on('complete', function (data) {
                    if (data.type == 'complete') {
                        map.remove(map.getAllOverlays('marker'));//清除所有
                        var points = route.getRoute(); //取得所有路径点的数据;
                        debugger;
                        for (var i = 0; i < points.length; i++) {
                            routeLineArray[i] = new AMap.LngLat(points[i].lng, points[i].lat);
                            linePoint[i] = [points[i].lng, points[i].lat];
                        }
                        polylineArr = setParallelPoints(points, length);//获取对应路径的平行线
                        var pixelLine1A = new AMap.Polyline({
                            path: polylineArr,
                            borderWeight: 2, // 线条宽度,默认为 1
                            strokeColor: 'green', // 线条颜色
                            lineJoin: 'round' // 折线拐点连接处样式
                        });
                        map.add(pixelLine1A);
                    }
                    route.destroy();
                });
            });

示例截图如下:

示例

完美

匹配范围内的点的话可以调用高德的JS数学计算库,很简单的,上官网看看

上一篇下一篇

猜你喜欢

热点阅读