Commit b89f516e authored by Starbeamrainbowlabs's avatar Starbeamrainbowlabs
Browse files

Ok, sot his isn't going to work. Let's try another algorithm instead :P

parent cb01b972
# Ramer Douglas Peucker Implementations
> My implementations of the ramer-douglas-peucker line simplification algorithm in JS and C#♯.
# Visvalingam’s Algorithm Implementations
> My implementations of the Visvalingam’s line simplification algorithm in JS and C#♯.
## Links
- https://bost.ocks.org/mike/simplify/
- http://karthaus.nl/rdp/
- https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
......@@ -10,7 +10,7 @@
<div class="debug-data">
<ul>
<li>Points: <output id="output-point-count"></output> &#10142; <output id="output-simple-point-count"></output></li>
<li>Epsilon: <input type="range" id="input-epsilon" value="2" min="0" max="1000" step="0.05" /> <output id="output-epsilon"></output>
<li>Epsilon: <input type="range" id="input-epsilon" value="2" min="0" max="100" step="0.05" /> <output id="output-epsilon"></output>
</ul>
</div>
......
......@@ -199,13 +199,21 @@ class Vector {
this.x / length,
this.y / length);
}
/**
* The length of this vector squared.
* @return {number} The length of this vector squared.
*/
get lengthSquared() {
return (this.x*this.x) + (this.y*this.y);
}
/**
* Get the length of the current vector.
* @return {number} The length of the current vector.
*/
get length() {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
return Math.sqrt(this.lengthSquared);
}
/**
......
......@@ -8,76 +8,42 @@ import Vector from './lib/Vector.js';
* @param {number} epsilon The amount of simplification to perform.
* @return {Vector[]} The simplfied line.
*/
function simplify_line(points, epsilon)
function simplify_line(points, min_area)
{
points = collapse_points(points);
let first_point = points[0],
last_point = points[points.length - 1];
let farthest_index = 0, farthest_distance = 0;
for (let i = 1; i < points.length - 1; i++) {
let next_distance = distance_from_line(first_point, last_point, points[i]);
if(next_distance > farthest_distance) {
farthest_index = i;
farthest_distance = next_distance;
let smallest_area = Number.MAX_SAFE_INTEGER, smallest_area_i = 1;
while(smallest_area > min_area)
{
for(let i = 1; i < points.length - 1; i++)
{
let next_area = triangle_area(points[i - 1], points[i], points[i + 1]);
if(next_area < smallest_area) {
smallest_area = next_area;
smallest_area_i = i;
}
}
}
// This point is far enough away that it's meaningful - recurse!
if(farthest_distance > epsilon) {
let left_side = simplify_line(points.slice(0, farthest_index + 1), epsilon),
right_side = simplify_line(points.slice(farthest_index), epsilon);
return [ ...left_side, ...right_side.slice(1) ];
}
return [
points[0],
points[points.length - 1]
];
}
/**
* Collapses sequences of points that are identical.
* @param {[Vector]} points The list of points to collapse.
* @return {[Vector]} The list of collapsed points.
*/
function collapse_points(points) {
let result = [];
for(let i = 0; i < points.length; i++) {
if(result.length > 0 && result[result.length - 1].equalTo(points[i]))
continue;
result.push(points[i]);
// Remove the central point of the smallest triangle
points.splice(smallest_area_i, 1);
}
return result;
}
/**
* Calculates the squared shortest distance between a point and the specified line.
* @param {Vector} line_start The point at which the line starts.
* @param {Vector} line_end The point at which the line ends.
* @param {Vector} point The point to calculate the distance for.
* @return {number} The shortest distance between the specified point
* and the specified line.
* Calculates the area of a triangle with the vertices a, b, and c
* @param {Vector} a The first vertex of the triangle.
* @param {Vector} b The second vertex of the triangle.
* @param {Vector} c The third and final vertex of the triangle.
* @return {number} The area of the triangle.
*/
function distance_from_line(line_start, line_end, point)
function triangle_area(a, b, c)
{
let main_line = line_end.clone().subtract(line_start);
let main_line_length = main_line.length;
if(main_line_length === 0)
return line_end.clone().subtract(point).length;
let projectionFactor = Math.max(0, Math.min(1,
point.clone().subtract(line_start).dotProduct(main_line) / main_line_length
));
let projection = main_line.clone().multiply(projectionFactor).add(line_start);
return projection.clone().subtract(point).length;
return Math.abs(
(
a.x * (b.x - c.x) +
b.x * (c.y - a.y) +
c.x * (a.y - b.y)
) / 2
);
}
export { simplify_line };
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment