Subversion Repositories eFlore/Projets.communes

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 jpm 1
<?php
2
/*========================================================
3
/* Implementation of Douglas-Peuker in PHP.
4
/*
5
/* Anthony Cartmell
6
/* ajcartmell@fonant.com
7
/*
8
/* This software is provided as-is, with no warranty.
9
/* Please use and modify freely for anything you like :)
10
/* Version 1.2 - 18 Aug 2009  Fixes problem with line of three points.
11
/*							Thanks to Craig Stanton http://craig.stanton.net.nz
12
/* Version 1.1 - 17 Jan 2007  Fixes nasty bug!
13
/*========================================================*/
14
 
15
class PolylineReducer {
16
	private $original_points = array();
17
	private $tolerance;
18
	private $tolerance_squared;
19
 
20
	public function __construct($geopoints_array) {
21
		foreach ($geopoints_array as $point) {
22
			$this->original_points[] = new Vector($point->latitude, $point->longitude);
23
		}
24
		/*----- Include first and last points -----*/
25
		$this->original_points[0]->include = true;
26
		$this->original_points[count($this->original_points)-1]->include = true;
27
	}
28
 
29
	/**
30
 	* Returns a list of GeoPoints for the simplest polyline that leaves
31
 	* no original point more than $tolerance away from it.
32
 	*
33
 	* @param float  $tolerance
34
 	* @return Geopoint array
35
 	*/
36
	public function SimplerLine($tolerance = 0.5) {
37
		$this->tolerance = $tolerance;
38
		$this->tolerance_squared = $tolerance * $tolerance;
39
		$this->DouglasPeucker(0, count($this->original_points) - 1);
40
		foreach ($this->original_points as $point) {
41
			if ($point->include) {
42
				$out[] = new GeoPoint($point->x, $point->y);
43
			}
44
		}
45
		return $out;
46
	}
47
 
48
	/**
49
 	* Douglas-Peuker polyline simplification algorithm. First draws single line
50
 	* from start to end. Then finds largest deviation from this straight line, and if
51
 	* greater than tolerance, includes that point, splitting the original line into
52
 	* two new lines. Repeats recursively for each new line created.
53
 	*
54
 	* @param int $start_vertex_index
55
 	* @param int $end_vertex_index
56
 	*/
57
	private function DouglasPeucker($start_vertex_index, $end_vertex_index) {
58
		if ($end_vertex_index <= $start_vertex_index + 1) // there is nothing to simplify
59
		return;
60
 
61
		// Make line from start to end
62
		$line = new Line($this->original_points[$start_vertex_index], $this->original_points[$end_vertex_index]);
63
 
64
		// Find largest distance from intermediate points to this line
65
		$max_dist_to_line_squared = 0;
66
		for ($index = $start_vertex_index+1; $index < $end_vertex_index; $index++) {
67
			$dist_to_line_squared = $line->DistanceToPointSquared($this->original_points[$index]);
68
			if ($dist_to_line_squared>$max_dist_to_line_squared) {
69
				$max_dist_to_line_squared = $dist_to_line_squared;
70
				$max_dist_index = $index;
71
			}
72
		}
73
 
74
		// Check max distance with tolerance
75
		if ($max_dist_to_line_squared > $this->tolerance_squared) {// error is worse than the tolerance
76
			// split the polyline at the farthest vertex from S
77
			$this->original_points[$max_dist_index]->include = true;
78
			// recursively simplify the two subpolylines
79
			$this->DouglasPeucker($start_vertex_index,$max_dist_index);
80
			$this->DouglasPeucker($max_dist_index,$end_vertex_index);
81
		}
82
		// else the approximation is OK, so ignore intermediate vertices
83
	}
84
}
85
?>