PolylineEncoder Class PHP
PolylineEncoder Class PHP
php
class PolylineEncoder {
private $numLevels;
private $zoomFactor;
private $verySmall;
private $forceEndpoints;
private $zoomLevelBreaks = 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]));
}
}
}
# 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.
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;
}
# 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.
private function createEncodings ($points, $dists) {
$encoded_points = "";
$plat = 0;
$plng = 0;
for($i=0; $i<count($points); $i++) {
if (isset($dists[$i]) || $i == 0 || $i == count($points)-1) {
$point = $points[$i];
$lat = $point->lat();
$lng = $point->lng();
$late5 = floor($lat * 1e5);
$lnge5 = 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.
private function computeLevel ($dd) {
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.
private function encodeLevels ($points, $dists, $absMaxDist) {
$encoded_levels = "";
if ($this->forceEndpoints) {
$encoded_levels .= $this->encodeNumber($this->numLevels-1);
}
else {
$encoded_levels .= $this->encodeNumber(
$this->numLevels-$this->computeLevel($absMaxDist)-1);
}
# This function is very similar to Google's, but I added some stuff to deal with
the double slash issue.
private function encodeNumber ($num) {
$encodeString = "";
while ($num >= 0x20) {
$nextValue = (0x20 | ($num & 0x1f)) + 63;
$encodeString .= chr($nextValue);
$num >>= 5;
}
$finalValue = $num + 63;
$encodeString .= chr($finalValue);
return $encodeString;
}
class PolylinePoint {
private $x;
private $y;
# Sample.
$pl = new PolylineEncoder;
$encode = $pl->dpEncode (array(
new PolylinePoint (-87.912756, 41.665831),
new PolylinePoint (-87.900167, 41.723928),
new PolylinePoint (-87.880056, 41.731831),
new PolylinePoint (-87.838155, 41.732732),
new PolylinePoint (-87.833355, 41.732932),
new PolylinePoint (-87.823455, 41.733032),
new PolylinePoint (-87.813654, 41.732932),
new PolylinePoint (-87.798153, 41.710932),
new PolylinePoint (-87.797553, 41.688132),
new PolylinePoint (-87.794851, 41.630333),
)
);
print_r ($encode);
?>