-
-
Notifications
You must be signed in to change notification settings - Fork 9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added an implementation of Douglas Peucker with resultCount input
- Loading branch information
1 parent
1987d7e
commit 634a690
Showing
1 changed file
with
146 additions
and
0 deletions.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
MPChartLib/src/main/java/com/github/mikephil/charting/data/filter/ApproximatorN.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
|
||
package com.github.mikephil.charting.data.filter; | ||
|
||
import java.util.ArrayList; | ||
|
||
/** | ||
* Implemented according to modified Douglas Peucker {@link} | ||
* http://psimpl.sourceforge.net/douglas-peucker.html | ||
*/ | ||
public class ApproximatorN | ||
{ | ||
public float[] reduceWithDouglasPeucker(float[] points, float resultCount) { | ||
|
||
int pointCount = points.length / 2; | ||
|
||
// if a shape has 2 or less points it cannot be reduced | ||
if (resultCount <= 2 || resultCount >= pointCount) | ||
return points; | ||
|
||
boolean[] keep = new boolean[pointCount]; | ||
|
||
// first and last always stay | ||
keep[0] = true; | ||
keep[pointCount - 1] = true; | ||
|
||
int currentStoredPoints = 2; | ||
|
||
ArrayList<Line> queue = new ArrayList<>(); | ||
Line line = new Line(0, pointCount - 1, points); | ||
queue.add(line); | ||
|
||
do { | ||
line = queue.remove(queue.size() - 1); | ||
|
||
// store the key | ||
keep[line.index] = true; | ||
|
||
// check point count tolerance | ||
currentStoredPoints += 1; | ||
|
||
if (currentStoredPoints == resultCount) | ||
break; | ||
|
||
// split the polyline at the key and recurse | ||
Line left = new Line(line.start, line.index, points); | ||
if (left.index > 0) { | ||
int insertionIndex = insertionIndex(left, queue); | ||
queue.add(insertionIndex, left); | ||
} | ||
|
||
Line right = new Line(line.index, line.end, points); | ||
if (right.index > 0) { | ||
int insertionIndex = insertionIndex(right, queue); | ||
queue.add(insertionIndex, right); | ||
} | ||
} while (queue.isEmpty()); | ||
|
||
float[] reducedEntries = new float[currentStoredPoints * 2]; | ||
|
||
for (int i = 0, i2 = 0, r2 = 0; i < currentStoredPoints; i++, r2 += 2) { | ||
if (keep[i]) { | ||
reducedEntries[i2++] = points[r2]; | ||
reducedEntries[i2++] = points[r2 + 1]; | ||
} | ||
} | ||
|
||
return reducedEntries; | ||
} | ||
|
||
private static float distanceToLine( | ||
float ptX, float ptY, float[] | ||
fromLinePoint1, float[] fromLinePoint2) { | ||
float dx = fromLinePoint2[0] - fromLinePoint1[0]; | ||
float dy = fromLinePoint2[1] - fromLinePoint1[1]; | ||
|
||
float dividend = Math.abs( | ||
dy * ptX - | ||
dx * ptY - | ||
fromLinePoint1[0] * fromLinePoint2[1] + | ||
fromLinePoint2[0] * fromLinePoint1[1]); | ||
double divisor = Math.sqrt(dx * dx + dy * dy); | ||
|
||
return (float)(dividend / divisor); | ||
} | ||
|
||
private static class Line { | ||
int start; | ||
int end; | ||
|
||
float distance = 0; | ||
int index = 0; | ||
|
||
Line(int start, int end, float[] points) { | ||
this.start = start; | ||
this.end = end; | ||
|
||
float[] startPoint = new float[]{points[start * 2], points[start * 2 + 1]}; | ||
float[] endPoint = new float[]{points[end * 2], points[end * 2 + 1]}; | ||
|
||
if (end <= start + 1) return; | ||
|
||
for (int i = start + 1, i2 = i * 2; i < end; i++, i2 += 2) { | ||
float distance = distanceToLine( | ||
points[i2], points[i2 + 1], | ||
startPoint, endPoint); | ||
|
||
if (distance > this.distance) { | ||
this.index = i; | ||
this.distance = distance; | ||
} | ||
} | ||
} | ||
|
||
boolean equals(final Line rhs) { | ||
return (start == rhs.start) && (end == rhs.end) && index == rhs.index; | ||
} | ||
|
||
boolean lessThan(final Line rhs) { | ||
return distance < rhs.distance; | ||
} | ||
} | ||
|
||
private static int insertionIndex(Line line, ArrayList<Line> queue) { | ||
int min = 0; | ||
int max = queue.size(); | ||
|
||
while (!queue.isEmpty()) { | ||
int midIndex = min + (max - min) / 2; | ||
Line midLine = queue.get(midIndex); | ||
|
||
if (midLine.equals(line)) { | ||
return midIndex; | ||
} | ||
else if (line.lessThan(midLine)) { | ||
// perform search in left half | ||
max = midIndex; | ||
} | ||
else { | ||
// perform search in right half | ||
min = midIndex + 1; | ||
} | ||
} | ||
|
||
return min; | ||
} | ||
} |
634a690
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this still released. It is perfect - we`d use that.