@@ -30,7 +30,7 @@ class Registry {
30
30
add ("cartesiantrianglearea" , new CartesianTriangleAreaCalculator ());
31
31
add ("trianglearea" , new TriangleAreaCalculator ());
32
32
add ("triangleheight" , new TriangleHeightCalculator ());
33
- add ("frecheterror " , new FrechetErrorCalculator ());
33
+ add ("simplefrecheterror " , new SimpleFrechetErrorCalculator ());
34
34
}
35
35
36
36
static void add (String name , SimplificationErrorCalculator calculator ) {
@@ -60,7 +60,8 @@ static SimplificationErrorCalculator byName(String calculatorName) {
60
60
}
61
61
62
62
/**
63
- * Calculate the triangle area using cartesian coordinates as described at https://en.wikipedia.org/wiki/Area_of_a_triangle
63
+ * Calculate the triangle area using cartesian coordinates as described at
64
+ * <a href="https://en.wikipedia.org/wiki/Area_of_a_triangle">Area of a triangle</a>
64
65
*/
65
66
class CartesianTriangleAreaCalculator implements SimplificationErrorCalculator {
66
67
@@ -75,8 +76,8 @@ public double calculateError(PointLike left, PointLike middle, PointLike right)
75
76
}
76
77
77
78
/**
78
- * Calculate the triangle area using geographic coordinates and Herons formula (side lengths)
79
- * as described at https://en.wikipedia.org/wiki/Area_of_a_triangle
79
+ * Calculate the triangle area using geographic coordinates and Herons formula (side lengths) as described at
80
+ * <a href=" https://en.wikipedia.org/wiki/Area_of_a_triangle">Area of a triangle</a>
80
81
*/
81
82
class TriangleAreaCalculator implements SimplificationErrorCalculator {
82
83
@@ -106,8 +107,8 @@ private double distance(PointLike a, PointLike b) {
106
107
}
107
108
108
109
/**
109
- * Calculate the triangle area using geographic coordinates and Herons formula (side lengths)
110
- * as described at https://en.wikipedia.org/wiki/Area_of_a_triangle, but scale the area down
110
+ * Calculate the triangle area using geographic coordinates and Herons formula (side lengths) as described at
111
+ * <a href=" https://en.wikipedia.org/wiki/Area_of_a_triangle">Area of a triangle</a> , but scale the area down
111
112
* by the inverse of the length of the base (left-right), which estimates the height of the triangle.
112
113
*/
113
114
class TriangleHeightCalculator implements SimplificationErrorCalculator {
@@ -124,7 +125,7 @@ public double calculateError(PointLike left, PointLike middle, PointLike right)
124
125
double db = s - b ;
125
126
double dc = s - c ;
126
127
if (da >= 0 && db >= 0 && dc >= 0 ) {
127
- // Herons formula, scaled by 1/a
128
+ // Herons formula, scaled by 2/a to estimate height
128
129
return 2.0 * Math .sqrt (s * da * db * dc ) / a ;
129
130
} else {
130
131
// rounding errors can cause flat triangles to have negative values, leading to NaN areas
@@ -137,7 +138,24 @@ private double distance(PointLike a, PointLike b) {
137
138
}
138
139
}
139
140
140
- class FrechetErrorCalculator implements SimplificationErrorCalculator {
141
+ /**
142
+ * Estimate the error as the height of the point above the base, but including support for back-paths
143
+ * in the sense that of the point to be removed is father from either end than the height, we take that distance instead.
144
+ * <p>
145
+ * Rotate all three points such that left-right are a horizontal line on the x-axis. Then the numbers of interest are:
146
+ * <ol>
147
+ * <li>height: y-value of middle point</li>
148
+ * <li>deltaL: -min(0, middleX - leftX)</li>
149
+ * <li>deltaR: max(0, middleX - rightX)</li>
150
+ * </ol>
151
+ * And the final error is: error = max(height, max(deltaL, deltaR))
152
+ * <p>
153
+ * This is not a full Frechet error calculation as it does not maintain state of all removed points,
154
+ * only calculating the error incurred by removal of the current point, as if the current simplified line is
155
+ * a good enough approximation of the original line. This restriction is currently true of all the
156
+ * calculations implemented so far.
157
+ */
158
+ class SimpleFrechetErrorCalculator implements SimplificationErrorCalculator {
141
159
142
160
@ Override
143
161
public double calculateError (PointLike left , PointLike middle , PointLike right ) {
@@ -157,8 +175,11 @@ public double calculateError(PointLike left, PointLike middle, PointLike right)
157
175
double rightYrotated = rightY * cos - rightX * sin ;
158
176
assert Math .abs (rightYrotated ) < 1e-10 ;
159
177
assert Math .abs (rightXrotated - len ) < len / 1e10 ;
160
- // Return distance to x-axis TODO: also include back-paths for Frechet distance calculation
161
- return Math .abs (middleYrotated );
178
+ double height = Math .abs (middleYrotated );
179
+ double deltaL = -Math .min (0 , middleXrotated );
180
+ double deltaR = Math .max (0 , middleXrotated - rightXrotated );
181
+ double backDistance = Math .max (deltaR , deltaL );
182
+ return Math .max (height , backDistance );
162
183
} else {
163
184
// If left and right points are co-located, we assume no consequence to removing the middle point
164
185
return 0.0 ;
0 commit comments