天天看點

google map 編碼折線問題

首先,引入PolylineEncoder.js

// PolylineEncoder.js copyright Mark McClure April/May 2007

//

// This software is placed explicitly in the public

// domain and may be freely distributed or modified.

// No warranty express or implied is provided.

//

// History:

// V 2.1 July 2007

// Minor modification in distance function to enhance

// speed. Suggested by Joel Rosenberg.

// V 2.0 May 2007.

// Major revisions include:

// Incorporation of Douglas-Peucker algorithm

// Encapsulation into the PolylineEncoder package.

// V 1.0 September 2006

// Original version based on simple vertex reduction

//

// This module defines a PolylineEncoder class to encode

// polylines for use with Google Maps together with a few

// auxiliary functions. Documentation at

// http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.html

//

// Google map reference including encoded polylines:

// http://www.google.com/apis/maps/documentation/

//

// Details on the algorithm used here:

// http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/

//

// Constructor:

// polylineEncoder = new PolylineEncoder(numLevels,

// zoomFactor, verySmall, forceEndpoints?);

// where numLevels and zoomFactor indicate how many

// different levels of magnification the polyline has

// and the change in magnification between those levels,

// verySmall indicates the length of a barely visible

// object at the highest zoom level, forceEndpoints

// indicates whether or not the endpoints should be

// visible at all zoom levels. forceEndpoints is

// optional with a default value of true. Probably

// should stay true regardless.

//

// Main methods:

// * PolylineEncoder.dpEncodeToPolyline(points,

// color?, weight?, opacity?)

// Accepts an array of latLng objects (see below) and

// optional style specifications. Returns an encoded

// polyline that may be directly overlayed on a Google

// Map. Requires that the Google Maps API be loaded.

//

// * PolylineEncoder.dpEncodeToPolygon(pointsArray,

// boundaryColor?, boundaryWeight?, boundaryOpacity?,

// fillColor?, fillOpacity?, fill?, outline?)

// Accepts an array of arrays latLng objects and

// optional style specifications. Returns an encoded

// polylgon that may be directly overlayed on a Google

// Map. Requires that the Google Maps API be loaded.

//

//

// Convenience classes and methods:

// * PolylineEncoder.latLng

// Constructor:

// myLatLng = new PolylineEncoder.latLng(y,x);

// The dpEncode* functions expect points in the

// form of an object with lat and lng methods. A

// GLatLng as defined by the Google Maps API does

// quite nicely. If you're developing a javascript

// without loading the API, however, you can use

// a PolylineEncoder.latLng for this purpose.

// //

// PolylineEncoder.pointsToLatLngs

// Sometimes your points are defined in terms of an

// array of arrays, rather than an array of latLngs.

// PolylineEncoder.pointsToLatLngs converts to an array

// of arrays to an array of latLngs for use by the

// dpEncode functions.

// //

// PolylineEncoder.pointsToGLatLngs

// PolylineEncoder.pointsToGLatLngs is analagous to the

// previous function, but it returns GLatLngs rather

// than PolylineEncoder.latLngs. The first function may

// be used independently of Google Maps. Use the second,

// if you need to use the result in a Goole Map function.

//

//

// Lower level methods

// PolylineEncoder.dpEncodeToJSON(points,

// color?, weight?, opacity?)

// Returns a legal argument to GPolyline.fromEncoded.

// //

// PolylineEncoder.dpEncode(points);

// This is where the real work is done. The return value

// is a JSON object with properties named encodedLevels,

// encdodedPoints and encodedPointsLiteral. These are

// strings which are acceptable input to the points and

// levels properties of the GPolyline.fromEncoded

// function. The encodedPoints string should be used for

// maps generated dynamically, while the

// encodedPointsLiteral string should be copied into a

// static document.

//

// The standard disclaimers, such as "use at your own risk,

// since I really don't have any idea what I'm doing," apply.

// The constructor

PolylineEncoder = function(numLevels, zoomFactor, verySmall, forceEndpoints) {

var i;

if(!numLevels) {

numLevels = 18;

}

if(!zoomFactor) {

zoomFactor = 2;

}

if(!verySmall) {

verySmall = 0.00001;

}

if(!forceEndpoints) {

forceEndpoints = true;

}

this.numLevels = numLevels;

this.zoomFactor = zoomFactor;

this.verySmall = verySmall;

this.forceEndpoints = forceEndpoints;

this.zoomLevelBreaks = new Array(numLevels);

for(i = 0; i < numLevels; i++) {

this.zoomLevelBreaks[i] = verySmall*Math.pow(zoomFactor, numLevels-i-1);

}

}

// The main function. Essentially the Douglas-Peucker

// algorithm, adapted for encoding. Rather than simply

// eliminating points, we record their from the

// segment which occurs at that recursive step. These

// distances are then easily converted to zoom levels.

PolylineEncoder.prototype.dpEncode = function(points) {

var absMaxDist = 0;

var stack = [];

var dists = new Array(points.length);

var maxDist, maxLoc, temp, first, last, current;

var i, encodedPoints, encodedLevels;

var segmentLength;

if(points.length > 2) {

stack.push([0, points.length-1]);

while(stack.length > 0) {

current = stack.pop();

maxDist = 0;

segmentLength = Math.pow(points[current[1]].lat()-points[current[0]].lat(),2) +

Math.pow(points[current[1]].lng()-points[current[0]].lng(),2);

for(i = current[0]+1; i < current[1]; i++) {

temp = this.distance(points[i],

points[current[0]], points[current[1]],

segmentLength);

if(temp > maxDist) {

maxDist = temp;

maxLoc = i;

if(maxDist > absMaxDist) {

absMaxDist = maxDist;

}

}

}

if(maxDist > this.verySmall) {

dists[maxLoc] = maxDist;

stack.push([current[0], maxLoc]);

stack.push([maxLoc, current[1]]);

}

}

}

encodedPoints = this.createEncodings(points, dists);

encodedLevels = this.encodeLevels(points, dists, absMaxDist);

return {

encodedPoints: encodedPoints,

encodedLevels: encodedLevels,

encodedPointsLiteral: encodedPoints.replace(g,"")

}

}

PolylineEncoder.prototype.dpEncodeToJSON = function(points,

color, weight, opacity) {

var result;

if(!opacity) {

opacity = 0.9;

}

if(!weight) {

weight = 3;

}

if(!color) {

color = "#0000ff";

}

result = this.dpEncode(points);

return {

color: color,

weight: weight,

opacity: opacity,

points: result.encodedPoints,

levels: result.encodedLevels,

numLevels: this.numLevels,

zoomFactor: this.zoomFactor

}

}

PolylineEncoder.prototype.dpEncodeToGPolyline = function(points,

color, weight, opacity) {

if(!opacity) {

opacity = 0.9;

}

if(!weight) {

weight = 3;

}

if(!color) {

color = "#0000ff";

}

return new GPolyline.fromEncoded(

this.dpEncodeToJSON(points, color, weight, opacity));

}

PolylineEncoder.prototype.dpEncodeToGPolygon = function(pointsArray,

boundaryColor, boundaryWeight, boundaryOpacity,

fillColor, fillOpacity, fill, outline) {

var i, boundaries;

if(!boundaryColor) {

boundaryColor = "#0000ff";

}

if(!boundaryWeight) {

boundaryWeight = 3;

}

if(!boundaryOpacity) {

boundaryOpacity = 0.9;

}

if(!fillColor) {

fillColor = boundaryColor;

}

if(!fillOpacity) {

fillOpacity = boundaryOpacity/3;

}

if(fill==undefined) {

fill = true;

}

if(outline==undefined) {

outline = true;

}

boundaries = new Array(0);

for(i=0; i<pointsArray.length; i++) {

boundaries.push(this.dpEncodeToJSON(pointsArray[i],

boundaryColor, boundaryWeight, boundaryOpacity));

}

return new GPolygon.fromEncoded({

polylines: boundaries,

color: fillColor,

opacity: fillOpacity,

fill: fill,

outline: outline

});

}

// distance(p0, p1, p2) computes the distance between the point p0

// and the segment [p1,p2]. This could probably be replaced with

// something that is a bit more numerically stable.

PolylineEncoder.prototype.distance = function(p0, p1, p2, segLength) {

var u, out;

if(p1.lat() === p2.lat() && p1.lng() === p2.lng()) {

out = Math.sqrt(Math.pow(p2.lat()-p0.lat(),2) + Math.pow(p2.lng()-p0.lng(),2));

}

else {

u = ((p0.lat()-p1.lat())*(p2.lat()-p1.lat())+(p0.lng()-p1.lng())*(p2.lng()-p1.lng()))/

segLength;

if(u <= 0) {

out = Math.sqrt(Math.pow(p0.lat() - p1.lat(),2) + Math.pow(p0.lng() - p1.lng(),2));

}

if(u >= 1) {

out = Math.sqrt(Math.pow(p0.lat() - p2.lat(),2) + Math.pow(p0.lng() - p2.lng(),2));

}

if(0 < u && u < 1) {

out = Math.sqrt(Math.pow(p0.lat()-p1.lat()-u*(p2.lat()-p1.lat()),2) +

Math.pow(p0.lng()-p1.lng()-u*(p2.lng()-p1.lng()),2));

}

}

return out;

}

// The createEncodings function is very similar to Google's

// http://www.google.com/apis/maps/documentation/polyline.js

// The key difference is that not all points are encoded,

// since some were eliminated by Douglas-Peucker.

PolylineEncoder.prototype.createEncodings = function(points, dists) {

var i, dlat, dlng;

var plat = 0;

var plng = 0;

var encoded_points = "";

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

if(dists[i] != undefined || i == 0 || i == points.length-1) {

var point = points[i];

var lat = point.lat();

var lng = point.lng();

var late5 = Math.floor(lat * 1e5);

var lnge5 = Math.floor(lng * 1e5);

dlat = late5 - plat;

dlng = lnge5 - plng;

plat = late5;

plng = lnge5;

encoded_points += this.encodeSignedNumber(dlat) +

this.encodeSignedNumber(dlng);

}

}

return encoded_points;

}

// This computes the appropriate zoom level of a point in terms of it's

// distance from the relevant segment in the DP algorithm. Could be done

// in terms of a logarithm, but this approach makes it a bit easier to

// ensure that the level is not too large.

PolylineEncoder.prototype.computeLevel = function(dd) {

var lev;

if(dd > this.verySmall) {

lev=0;

while(dd < this.zoomLevelBreaks[lev]) {

lev++;

}

return lev;

}

}

// Now we can use the previous function to march down the list

// of points and encode the levels. Like createEncodings, we

// ignore points whose distance (in dists) is undefined.

PolylineEncoder.prototype.encodeLevels = function(points, dists, absMaxDist) {

var i;

var encoded_levels = "";

if(this.forceEndpoints) {

encoded_levels += this.encodeNumber(this.numLevels-1)

} else {

encoded_levels += this.encodeNumber(

this.numLevels-this.computeLevel(absMaxDist)-1)

}

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

if(dists[i] != undefined) {

encoded_levels += this.encodeNumber(

this.numLevels-this.computeLevel(dists[i])-1);

}

}

if(this.forceEndpoints) {

encoded_levels += this.encodeNumber(this.numLevels-1)

} else {

encoded_levels += this.encodeNumber(

this.numLevels-this.computeLevel(absMaxDist)-1)

}

return encoded_levels;

}

// This function is very similar to Google's, but I added

// some stuff to deal with the double slash issue.

PolylineEncoder.prototype.encodeNumber = function(num) {

var encodeString = "";

var nextValue, finalValue;

while (num >= 0x20) {

nextValue = (0x20 | (num & 0x1f)) + 63;

// if (nextValue == 92) {

// encodeString += (String.fromCharCode(nextValue));

// }

encodeString += (String.fromCharCode(nextValue));

num >>= 5;

}

finalValue = num + 63;

// if (finalValue == 92) {

// encodeString += (String.fromCharCode(finalValue));

// }

encodeString += (String.fromCharCode(finalValue));

return encodeString;

}

// This one is Google's verbatim.

PolylineEncoder.prototype.encodeSignedNumber = function(num) {

var sgn_num = num << 1;

if (num < 0) {

sgn_num = ~(sgn_num);

}

return(this.encodeNumber(sgn_num));

}

// The remaining code defines a few convenience utilities.

// PolylineEncoder.latLng

PolylineEncoder.latLng = function(y, x) {

this.y = y;

this.x = x;

}

PolylineEncoder.latLng.prototype.lat = function() {

return this.y;

}

PolylineEncoder.latLng.prototype.lng = function() {

return this.x;

}

// PolylineEncoder.pointsToLatLngs

PolylineEncoder.pointsToLatLngs = function(points) {

var i, latLngs;

latLngs = new Array(0);

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

latLngs.push(new PolylineEncoder.latLng(points[i][0], points[i][1]));

}

return latLngs;

}

// PolylineEncoder.pointsToGLatLngs

PolylineEncoder.pointsToGLatLngs = function(points) {

var i, gLatLngs;

gLatLngs = new Array(0);

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

gLatLngs.push(new GLatLng(points[i][0], points[i][1]));

}

return gLatLngs;

}

然後根據你所求出的所有點的坐标

var count = trackList.length; //坐标點的個數

var points = new Array(0); 

var polylineEncoder = new PolylineEncoder(); //定義編碼對象

for ( var j = 0; j < count; j++) {

      var track = trackList[j];

       points[j] = new GLatLng(parseFloat(trackList[j].lat),parseFloat(trackList[j].lng));   //得到坐标點數組

}

polyline = polylineEncoder.dpEncodeToGPolyline(points,'#ff0000',2,0.5);   //根據 PolylineEncoder.js自動json編碼

 map.addOverlay(polyline);  //地圖上添加折線  一次性畫出所有折線

繼續閱讀