JS绘制折线等距平行线(google地图绘制)

设一段折线a b c与其平行折线 a ' b ~ c间的垂直距-->接下图:

 

 

 

html+js+googlemap实现源码(实现了自画折线的两条等距平行线及包围起来的多边形区域):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

    <title>testline2.html</title>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> 

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script> 

<script type="text/javascript">

/*

 * 实现功能:计算折线的两条等距平行线点集,并绘制两平行线组合成的多边形

 */

var map; // google地图对象引用

var poly;// 主线路

var poly1, poly2;// 平行线

var polygon;// 多边形

// 定义平行线路点集

var ParallelA = [], ParallelB = [];

var Distance = 0;// 平行线与主线距离

 

// 加载GOOGLE地图   

function initialize() {     

var latlng = new google.maps.LatLng(28.227, 112.944);     

var myOptions = {       

zoom: 12,       

center: latlng,   

scaleControl: true,//比例尺可见    

mapTypeId: google.maps.MapTypeId.ROADMAP     

};     

map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

// 折线属性   

var polyOptions = {

     strokeColor: '#000000',

     strokeOpacity: 1.0,

     strokeWeight: 1

   }

   poly = new google.maps.Polyline(polyOptions);

   poly.setMap(map);   

  

   // Add a listener for the click event

   google.maps.event.addListener(map, 'click', addLatLng);

}

 

/**

   * Handles click events on a map, and adds a new point to the Polyline.

   * @param {MouseEvent} mouseEvent

   */

function addLatLng(event) {

   var path = poly.getPath();

   // Because path is an MVCArray, we can simply append a new coordinate

   // and it will automatically appear

   path.push(event.latLng);

   // Add a new marker at the new plotted point on the polyline.

   //var marker = new google.maps.Marker({

     // position: event.latLng,

     // title: '#' + path.getLength(),

     // map: map

   //});  

  

}

/**

 * 根据已知折线点集计算指定距离的两条平行线的点集

 * @param {MVCArray<LatLng>} 

   * @param {L} 主线和平行线的距离(单位:米)

 */

function setParallelPoints(MVCArray, L){

ParallelA = [];

ParallelB = [];

var polytemp = [], polyArr = [];

// 取出原线路点集

for(var i=0; i< MVCArray.getLength(); i++ ){

polytemp.push(MVCArray.getAt(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_latlng = getParallelPoint(p0, p1, p2, Distance);

lat1 = p1.lat() + d_latlng.lat;

lng1 = p1.lng() + d_latlng.lng;

lat2 = p1.lat() - d_latlng.lat;

lng2 = p1.lng() - d_latlng.lng;

ParallelA.push(new google.maps.LatLng(lat1, lng1));

ParallelB.push(new google.maps.LatLng(lat2, lng2));

poly1.setPath(ParallelA);

   poly2.setPath(ParallelB);

}

}

/**

 * 优化主线点集

 * 折线点集首尾加上辅助点,去掉点间距离过紧的多余点

 * @param {oldArr} 折线点集数组

 * @param {L} 相邻两点间直线距离标准(单位:米)

 * @return newArr 新折线点集数组

 */

function initPolyline(oldArr, L){

var newArr = [];

if(oldArr.length < 2)

return oldArr;

// 加入起始辅助点

newArr.push(new google.maps.LatLng(

oldArr[0].lat()*2-oldArr[1].lat(), 

oldArr[0].lng()*2-oldArr[1].lng()));

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 google.maps.LatLng(

oldArr[oldArr.length-1].lat()*2-oldArr[oldArr.length-2].lat(), 

oldArr[oldArr.length-1].lng()*2-oldArr[oldArr.length-2].lng()));

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 {d_lat} 纬度差值

 * @return 长度差值

 */

function latToLen(d_lat){

var L = 10002150; // 半个经线长度(经线圈的1/4),对应90°纬度

      var len = d_lat*L/90;

      return len;

}

/**

 * 纬线方向长度转化成经度

 * @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 {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;

}

// 画线

function drawParallel(){

ParallelA = [], ParallelB = [];

if (poly1 != null){

poly1.setMap(null);

poly1 = null;

}

if (poly2 != null){

poly2.setMap(null);

poly2 = null;

}

// 折线属性A   

var polyOptions1 = {

     strokeColor: '#FF0000',

     strokeOpacity: 1.0,

     strokeWeight: 1

     //path: ParallelA

   }

  

// 折线属性B   

var polyOptions2 = {

     strokeColor: '#FF0000',

     strokeOpacity: 1.0,

     strokeWeight: 1

     //path: ParallelB

   }

     

   poly1 = new google.maps.Polyline(polyOptions1);

   poly1.setMap(map);

  

   poly2 = new google.maps.Polyline(polyOptions2);

   poly2.setMap(map);

  

   Distance = document.getElementById("v_length").value;

   setParallelPoints(poly.getPath(), Distance);

}

/**

 * 组合两平行线点集,绘制多边形

 */

function drawPolygon(){

if (polygon != null){

polygon.setMap(null);

polygon = null;

}

polygon = new google.maps.Polygon({

    strokeColor: "#FF0000",

    strokeOpacity: 0.8,

    strokeWeight: 2,

    fillColor: "#FF0000",

    fillOpacity: 0.35

});

polygon.setMap(map);

var gonArr = ParallelA;

for (var i=ParallelB.length-1; i>=0; i--){

gonArr.push(ParallelB[i]);

}

gonArr.push(gonArr[0]);

polygon.setPath(gonArr);

}

 

/**

 * 测量主线路距离

 */

function measureDistance(){

var mvaArr = poly.getPath();

var tempArr = []

// 取出原线路点集

for(var i=1; i< mvaArr.getLength()-1; i++ ){

tempArr.push(mvaArr.getAt(i));

}

var leng = getLongs(tempArr);

leng = Math.round(leng);

document.getElementById("dis_value").value = leng;

}

/**

 * 折线距离封装函数

 * @param {Array} points  LatLng数组

 * @return {number} 距离 单位:米

 */

function getLongs(points){

var longs = 0;

if(points.length < 2)

return 0;

for(var i = 0; i< points.length-1; i++){

longs += getDistance(points[i], points[i+1]);

}

return longs;

}

/**

 * 求两点间距离

 * @param {LatLng} startP 起点

 * @param {LatLng} endP 终点

 * @return {number} 距离 单位:米

 */

function getDistance(startP,endP){

    // 大地反算,知道两点的纬度和经度,

// 求大地线的长度(和投影后的平面距离至差1cm左右). Help by LinXB

    // <param name="startP">起点的纬度和经度,单位:度</param>

    // <param name="endP">终点的纬度和经度,单位:度</param>

    // <returns>输出:距离,单位:m</returns>

    // 输入:170181690毫秒,475273606, 170181698, 475273509,结果是2.05米

    var x, y, result;

    var R = 6378137.0; //84椭球

    x=(endP.lng()-startP.lng())*Math.PI*R*Math.cos(((startP.lat()+endP.lat())/2)*Math.PI/180)/180;

    y=Math.PI*(endP.lat() - startP.lat())*R/180;

    result = Math.sqrt(x * x + y * y);

    return result;

}

function clearLines(){

ParallelA = [], ParallelB = [];

poly.setPath([]);

if (poly1 != null){

poly1.setMap(null);

poly1 = null;

}

if (poly2 != null){

poly2.setMap(null);

poly2 = null;

}

if (polygon != null){

polygon.setMap(null);

polygon = null;

}

}

</script> 

  </head> 

  <body οnlοad="initialize()">   

   <div id="map_canvas" style="width:76%; height:600px; left:2%; float:left;"></div> 

   <div id="toolbar" style="width:20%; height:400px; left:80%; float:right;">

   <label for="v_length">平行线距离</label>

   <input id="v_length" type=text style="width:60px;" value="50">米

   <input type=button value="画 线" οnclick="drawParallel()"><br>

   <input type=button value="画矩形" οnclick="drawPolygon()"><br> 

   <input type=button value="清 空" οnclick="clearLines();"><br> 

   <input type=button value="线路测距" οnclick="measureDistance()">

   <input id="dis_value" type=text style="width:60px;" value="">米<br>

   </div>

  </body> 

</html>

效果图:

 

ps:文件中注释可能还存在些许出入。浏览器打开文件后,不做任何按钮操作,鼠标在地图上点击即可生成原始折线。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值