-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathsimplify.php
129 lines (90 loc) · 2.35 KB
/
simplify.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
function simplify($points, $tolerance = 1, $highestQuality = false) {
if (count($points) < 2) return $points;
$sqTolerance = $tolerance * $tolerance;
if (!$highestQuality) {
$points = simplifyRadialDistance($points, $sqTolerance);
}
$points = simplifyDouglasPeucker($points, $sqTolerance);
return $points;
}
function getSquareDistance($p1, $p2) {
$dx = $p1[0] - $p2[0];
$dy = $p1[1] - $p2[1];
return $dx * $dx + $dy * $dy;
}
function getSquareSegmentDistance($p, $p1, $p2) {
$x = $p1[0];
$y = $p1[1];
$dx = $p2[0] - $x;
$dy = $p2[1] - $y;
if (abs($dx) + abs($dy) > 0.000001) {
$t = (($p[0] - $x) * $dx + ($p[1] - $y) * $dy) / ($dx * $dx + $dy * $dy);
if ($t > 1) {
$x = $p2[0];
$y = $p2[1];
} else if ($t > 0) {
$x += $dx * $t;
$y += $dy * $t;
}
}
$dx = $p[0] - $x;
$dy = $p[1] - $y;
return $dx * $dx + $dy * $dy;
}
function simplifyRadialDistance($points, $sqTolerance) { // distance-based simplification
$len = count($points);
$prevPoint = $points[0];
$newPoints = array($prevPoint);
$point = null;
for ($i = 1; $i < $len; $i++) {
$point = $points[$i];
if (getSquareDistance($point, $prevPoint) > $sqTolerance) {
array_push($newPoints, $point);
$prevPoint = $point;
}
}
if ($prevPoint !== $point) {
array_push($newPoints, $point);
}
return $newPoints;
}
// simplification using optimized Douglas-Peucker algorithm with recursion elimination
function simplifyDouglasPeucker($points, $sqTolerance) {
$len = count($points);
if( $len <= 1 )
return $points;
$markers = array_fill ( 0 , $len - 1, null);
$first = 0;
$last = $len - 1;
$firstStack = array();
$lastStack = array();
$newPoints = array();
$markers[$first] = $markers[$last] = 1;
while ($last) {
$maxSqDist = 0;
for ($i = $first + 1; $i < $last; $i++) {
$sqDist = getSquareSegmentDistance($points[$i], $points[$first], $points[$last]);
if ($sqDist > $maxSqDist) {
$index = $i;
$maxSqDist = $sqDist;
}
}
if ($maxSqDist > $sqTolerance) {
$markers[$index] = 1;
array_push($firstStack, $first);
array_push($lastStack, $index);
array_push($firstStack, $index);
array_push($lastStack, $last);
}
$first = array_pop($firstStack);
$last = array_pop($lastStack);
}
for ($i = 0; $i < $len; $i++) {
if ($markers[$i]) {
array_push($newPoints, $points[$i]);
}
}
return $newPoints;
}
?>