设一段折线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:文件中注释可能还存在些许出入。浏览器打开文件后,不做任何按钮操作,鼠标在地图上点击即可生成原始折线。