/  6
 
<?php# Ported from Mark McClure's PolylineEncoder.js script.// 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.//// 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.//// Convenience classes and methods:// * PolylinePoint// Constructor:// myLatLng = new PolylinePoint(lat,lng);// 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 PolylinePoint for this purpose.//// 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.class PolylineEncoder {private $numLevels;private $zoomFactor;private $verySmall;private $forceEndpoints;private $zoomLevelBreaks = array(); public function __construct ($numLevels=18, $zoomFactor=2, $verySmall=0.00001,$forceEndpoints=true) {$this->numLevels = $numLevels;$this->zoomFactor = $zoomFactor;$this->verySmall = $verySmall;$this->forceEndpoints = $forceEndpoints;for($i=0; $i<$numLevels; $i++) {$this->zoomLevelBreaks[$i] = $verySmall * pow($zoomFactor, $numLevels-$i-1);}}# The main function. Essentially the Douglas-Peucker algorithm, adapted forencoding. Rather than simply# eliminating points, we record their from the segment which occurs at thatrecursive step. These# distances are then easily converted to zoom levels.public function dpEncode ($points) {$absMaxDist = 0;$stack = array();$dists = array(); if(count($points) > 2) {array_push ($stack, array(0, count($points)-1));while(count($stack) > 0) {$current = array_pop($stack);$maxDist = 0;$segmentLength = pow($points[$current[1]]->lat()-$points[$current[0]]->lat(),2) +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;array_push ($stack, array($current[0], $maxLoc));
 
array_push ($stack, array($maxLoc, $current[1]));}}} $encodedPoints = $this->createEncodings ($points, $dists);$encodedLevels = $this->encodeLevels ($points, $dists, $absMaxDist);return array ('encodedPoints' => $encodedPoints,'encodedLevels' => $encodedLevels,'encodedPointsLiteral' => str_replace('\\',"\\\\",$encodedPoints));}public function dpEncodeToJson ($points, $color='#0000ff', $weight=3,$opacity=0.9) {$result = $this->dpEncode(points);return array ('color' => $color,'weight' => $weight,'opacity' => $opacity,'points' => $result['encodedPoints'],'levels' => $result['encodedLevels'],'numLevels' => $this->numLevels,'zoomFactor' => $this->zoomFactor);}# distance(p0, p1, p2) computes the distance between the point p0 and thesegment [p1,p2]. This could probably be replaced with# something that is a bit more numerically stable.private function distance ($p0, $p1, $p2, $segLength) {$out = null;if($p1->lat() === $p2->lat() && $p1->lng() === $p2->lng()) {$out = sqrt(pow($p2->lat()-$p0->lat(),2) + 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 = sqrt(pow($p0->lat() - $p1->lat(),2) + pow($p0->lng() - $p1->lng(),2));}if($u >= 1) {$out = sqrt(pow($p0->lat() - $p2->lat(),2) + pow($p0->lng() - $p2->lng(),2));}if(0 < $u && $u < 1) {$out = sqrt(pow($p0->lat()-$p1->lat()-$u*($p2->lat()-$p1->lat()),2) +pow($p0->lng()-$p1->lng()-$u*($p2->lng()-$p1->lng()),2));}}return $out;}

Share & Embed

More from this user

Add a Comment

Characters: ...