Comparing version 1.1.0 to 1.1.1
@@ -7,3 +7,2 @@ 'use strict' | ||
var boxIntersect = require('box-intersect') | ||
var compareCell = require('compare-cell') | ||
var segseg = require('robust-segment-intersect') | ||
@@ -18,19 +17,15 @@ var rat = require('big-rat') | ||
//Bounds on a rational number when rounded to a float | ||
function boundRat(r) { | ||
// Bounds on a rational number when rounded to a float | ||
function boundRat (r) { | ||
var f = ratToFloat(r) | ||
var cmp = ratCmp(rat(f), r) | ||
if(cmp < 0) { | ||
return [f, nextafter(f, Infinity)] | ||
} else if(cmp > 0) { | ||
return [nextafter(f, -Infinity), f] | ||
} else { | ||
return [f, f] | ||
} | ||
return [ | ||
nextafter(f, -Infinity), | ||
nextafter(f, Infinity) | ||
] | ||
} | ||
//Convert a list of edges in a pslg to bounding boxes | ||
function boundEdges(points, edges) { | ||
// Convert a list of edges in a pslg to bounding boxes | ||
function boundEdges (points, edges) { | ||
var bounds = new Array(edges.length) | ||
for(var i=0; i<edges.length; ++i) { | ||
for (var i = 0; i < edges.length; ++i) { | ||
var e = edges[i] | ||
@@ -40,6 +35,7 @@ var a = points[e[0]] | ||
bounds[i] = [ | ||
Math.min(a[0], b[0]), | ||
Math.min(a[1], b[1]), | ||
Math.max(a[0], b[0]), | ||
Math.max(a[1], b[1]) ] | ||
nextafter(Math.min(a[0], b[0]), -Infinity), | ||
nextafter(Math.min(a[1], b[1]), -Infinity), | ||
nextafter(Math.max(a[0], b[0]), Infinity), | ||
nextafter(Math.max(a[1], b[1]), Infinity) | ||
] | ||
} | ||
@@ -49,8 +45,13 @@ return bounds | ||
//Convert a list of points into bounding boxes by duplicating coords | ||
function boundPoints(points) { | ||
// Convert a list of points into bounding boxes by duplicating coords | ||
function boundPoints (points) { | ||
var bounds = new Array(points.length) | ||
for(var i=0; i<points.length; ++i) { | ||
for (var i = 0; i < points.length; ++i) { | ||
var p = points[i] | ||
bounds[i] = [ p[0], p[1], p[0], p[1] ] | ||
bounds[i] = [ | ||
nextafter(p[0], -Infinity), | ||
nextafter(p[1], -Infinity), | ||
nextafter(p[0], Infinity), | ||
nextafter(p[1], Infinity) | ||
] | ||
} | ||
@@ -60,11 +61,11 @@ return bounds | ||
//Find all pairs of crossing edges in a pslg (given edge bounds) | ||
function getCrossings(points, edges, edgeBounds) { | ||
// Find all pairs of crossing edges in a pslg (given edge bounds) | ||
function getCrossings (points, edges, edgeBounds) { | ||
var result = [] | ||
boxIntersect(edgeBounds, function(i, j) { | ||
boxIntersect(edgeBounds, function (i, j) { | ||
var e = edges[i] | ||
var f = edges[j] | ||
if(e[0] === f[0] || e[0] === f[1] || | ||
e[1] === f[0] || e[1] === f[1]) { | ||
return | ||
if (e[0] === f[0] || e[0] === f[1] || | ||
e[1] === f[0] || e[1] === f[1]) { | ||
return | ||
} | ||
@@ -75,3 +76,3 @@ var a = points[e[0]] | ||
var d = points[f[1]] | ||
if(segseg(a, b, c, d)) { | ||
if (segseg(a, b, c, d)) { | ||
result.push([i, j]) | ||
@@ -83,8 +84,8 @@ } | ||
//Find all pairs of crossing vertices in a pslg (given edge/vert bounds) | ||
function getTJunctions(points, edges, edgeBounds, vertBounds) { | ||
// Find all pairs of crossing vertices in a pslg (given edge/vert bounds) | ||
function getTJunctions (points, edges, edgeBounds, vertBounds) { | ||
var result = [] | ||
boxIntersect(edgeBounds, vertBounds, function(i, v) { | ||
boxIntersect(edgeBounds, vertBounds, function (i, v) { | ||
var e = edges[i] | ||
if(e[0] === v || e[1] === v) { | ||
if (e[0] === v || e[1] === v) { | ||
return | ||
@@ -95,3 +96,3 @@ } | ||
var b = points[e[1]] | ||
if(segseg(a, b, p, p)) { | ||
if (segseg(a, b, p, p)) { | ||
result.push([i, v]) | ||
@@ -103,11 +104,14 @@ } | ||
// Cut edges along crossings/tjunctions | ||
function cutEdges (floatPoints, edges, crossings, junctions, useColor) { | ||
var i, e | ||
//Cut edges along crossings/tjunctions | ||
function cutEdges(floatPoints, edges, crossings, junctions, useColor) { | ||
//Convert crossings into tjunctions by constructing rational points | ||
var ratPoints = [] | ||
for(var i=0; i<crossings.length; ++i) { | ||
// Convert crossings into tjunctions by constructing rational points | ||
var ratPoints = floatPoints.map((p) => [ | ||
rat(p[0]), | ||
rat(p[1]) | ||
]) | ||
for (i = 0; i < crossings.length; ++i) { | ||
var crossing = crossings[i] | ||
var e = crossing[0] | ||
e = crossing[0] | ||
var f = crossing[1] | ||
@@ -121,7 +125,8 @@ var ee = edges[e] | ||
ratVec(floatPoints[ef[1]])) | ||
if(!x) { | ||
//Segments are parallel, should already be handled by t-junctions | ||
if (!x) { | ||
// Segments are parallel, should already be handled by t-junctions | ||
continue | ||
} | ||
var idx = ratPoints.length + floatPoints.length | ||
var idx = floatPoints.length | ||
floatPoints.push([ratToFloat(x[0]), ratToFloat(x[1])]) | ||
ratPoints.push(x) | ||
@@ -131,23 +136,16 @@ junctions.push([e, idx], [f, idx]) | ||
//Sort tjunctions | ||
function getPoint(idx) { | ||
if(idx >= floatPoints.length) { | ||
return ratPoints[idx-floatPoints.length] | ||
} | ||
var p = floatPoints[idx] | ||
return [ rat(p[0]), rat(p[1]) ] | ||
} | ||
junctions.sort(function(a, b) { | ||
if(a[0] !== b[0]) { | ||
// Sort tjunctions | ||
junctions.sort(function (a, b) { | ||
if (a[0] !== b[0]) { | ||
return a[0] - b[0] | ||
} | ||
var u = getPoint(a[1]) | ||
var v = getPoint(b[1]) | ||
var u = ratPoints[a[1]] | ||
var v = ratPoints[b[1]] | ||
return ratCmp(u[0], v[0]) || ratCmp(u[1], v[1]) | ||
}) | ||
//Split edges along junctions | ||
for(var i=junctions.length-1; i>=0; --i) { | ||
// Split edges along junctions | ||
for (i = junctions.length - 1; i >= 0; --i) { | ||
var junction = junctions[i] | ||
var e = junction[0] | ||
e = junction[0] | ||
@@ -158,6 +156,6 @@ var edge = edges[e] | ||
//Check if edge is not lexicographically sorted | ||
// Check if edge is not lexicographically sorted | ||
var a = floatPoints[s] | ||
var b = floatPoints[t] | ||
if(((a[0] - b[0]) || (a[1] - b[1])) < 0) { | ||
if (((a[0] - b[0]) || (a[1] - b[1])) < 0) { | ||
var tmp = s | ||
@@ -168,17 +166,17 @@ s = t | ||
//Split leading edge | ||
// Split leading edge | ||
edge[0] = s | ||
var last = edge[1] = junction[1] | ||
//If we are grouping edges by color, remember to track data | ||
// If we are grouping edges by color, remember to track data | ||
var color | ||
if(useColor) { | ||
if (useColor) { | ||
color = edge[2] | ||
} | ||
//Split other edges | ||
while(i > 0 && junctions[i-1][0] === e) { | ||
// Split other edges | ||
while (i > 0 && junctions[i - 1][0] === e) { | ||
var junction = junctions[--i] | ||
var next = junction[1] | ||
if(useColor) { | ||
if (useColor) { | ||
edges.push([last, next, color]) | ||
@@ -191,4 +189,4 @@ } else { | ||
//Add final edge | ||
if(useColor) { | ||
// Add final edge | ||
if (useColor) { | ||
edges.push([last, t, color]) | ||
@@ -200,52 +198,67 @@ } else { | ||
//Return constructed rational points | ||
// Return constructed rational points | ||
return ratPoints | ||
} | ||
//Merge overlapping points | ||
function dedupPoints(floatPoints, ratPoints, floatBounds) { | ||
var numPoints = floatPoints.length + ratPoints.length | ||
var uf = new UnionFind(numPoints) | ||
// Merge overlapping points | ||
function dedupPoints (floatPoints, ratPoints, floatBounds) { | ||
var numPoints = ratPoints.length | ||
var uf = new UnionFind(numPoints) | ||
//Compute rational bounds | ||
var bounds = floatBounds | ||
for(var i=0; i<ratPoints.length; ++i) { | ||
// Compute rational bounds | ||
var bounds = [] | ||
for (var i = 0; i < ratPoints.length; ++i) { | ||
var p = ratPoints[i] | ||
var xb = boundRat(p[0]) | ||
var yb = boundRat(p[1]) | ||
bounds.push([ xb[0], yb[0], xb[1], yb[1] ]) | ||
floatPoints.push([ ratToFloat(p[0]), ratToFloat(p[1]) ]) | ||
bounds.push([ | ||
nextafter(xb[0], -Infinity), | ||
nextafter(yb[0], -Infinity), | ||
nextafter(xb[1], Infinity), | ||
nextafter(yb[1], Infinity) | ||
]) | ||
} | ||
//Link all points with over lapping boxes | ||
boxIntersect(bounds, function(i, j) { | ||
// Link all points with over lapping boxes | ||
boxIntersect(bounds, function (i, j) { | ||
uf.link(i, j) | ||
}) | ||
//Call find on each point to get a relabeling | ||
var ptr = 0 | ||
// Do 1 pass over points to combine points in label sets | ||
var noDupes = true | ||
var labels = new Array(numPoints) | ||
for(var i=0; i<numPoints; ++i) { | ||
for (var i = 0; i < numPoints; ++i) { | ||
var j = uf.find(i) | ||
if(j === i) { | ||
//If not a duplicate, then don't bother | ||
if (j !== i) { | ||
// Clear no-dupes flag, zero out label | ||
noDupes = false | ||
// Make each point the top-left point from its cell | ||
floatPoints[j] = [ | ||
Math.min(floatPoints[i][0], floatPoints[j][0]), | ||
Math.min(floatPoints[i][1], floatPoints[j][1]) | ||
] | ||
} | ||
} | ||
// If no duplicates, return null to signal termination | ||
if (noDupes) { | ||
return null | ||
} | ||
var ptr = 0 | ||
for (var i = 0; i < numPoints; ++i) { | ||
var j = uf.find(i) | ||
if (j === i) { | ||
labels[i] = ptr | ||
floatPoints[ptr++] = floatPoints[i] | ||
} else { | ||
//Clear no-dupes flag, zero out label | ||
noDupes = false | ||
labels[i] = -1 | ||
} | ||
} | ||
floatPoints.length = ptr | ||
//If no duplicates, return null to signal termination | ||
if(noDupes) { | ||
return null | ||
} | ||
//Do a second pass to fix up missing labels | ||
for(var i=0; i<numPoints; ++i) { | ||
if(labels[i] < 0) { | ||
// Do a second pass to fix up missing labels | ||
for (var i = 0; i < numPoints; ++i) { | ||
if (labels[i] < 0) { | ||
labels[i] = labels[uf.find(i)] | ||
@@ -255,15 +268,15 @@ } | ||
//Return resulting union-find data structure | ||
// Return resulting union-find data structure | ||
return labels | ||
} | ||
function compareLex2(a,b) { return (a[0]-b[0]) || (a[1]-b[1]) } | ||
function compareLex3(a,b) { | ||
function compareLex2 (a, b) { return (a[0] - b[0]) || (a[1] - b[1]) } | ||
function compareLex3 (a, b) { | ||
var d = (a[0] - b[0]) || (a[1] - b[1]) | ||
if(d) { | ||
if (d) { | ||
return d | ||
} | ||
if(a[2] < b[2]) { | ||
if (a[2] < b[2]) { | ||
return -1 | ||
} else if(a[2] > b[2]) { | ||
} else if (a[2] > b[2]) { | ||
return 1 | ||
@@ -274,9 +287,9 @@ } | ||
//Remove duplicate edge labels | ||
function dedupEdges(edges, labels, useColor) { | ||
if(edges.length === 0) { | ||
// Remove duplicate edge labels | ||
function dedupEdges (edges, labels, useColor) { | ||
if (edges.length === 0) { | ||
return | ||
} | ||
if(labels) { | ||
for(var i=0; i<edges.length; ++i) { | ||
if (labels) { | ||
for (var i = 0; i < edges.length; ++i) { | ||
var e = edges[i] | ||
@@ -289,3 +302,3 @@ var a = labels[e[0]] | ||
} else { | ||
for(var i=0; i<edges.length; ++i) { | ||
for (var i = 0; i < edges.length; ++i) { | ||
var e = edges[i] | ||
@@ -298,3 +311,3 @@ var a = e[0] | ||
} | ||
if(useColor) { | ||
if (useColor) { | ||
edges.sort(compareLex3) | ||
@@ -305,6 +318,6 @@ } else { | ||
var ptr = 1 | ||
for(var i=1; i<edges.length; ++i) { | ||
var prev = edges[i-1] | ||
for (var i = 1; i < edges.length; ++i) { | ||
var prev = edges[i - 1] | ||
var next = edges[i] | ||
if(next[0] === prev[0] && next[1] === prev[1] && | ||
if (next[0] === prev[0] && next[1] === prev[1] && | ||
(!useColor || next[2] === prev[2])) { | ||
@@ -318,8 +331,13 @@ continue | ||
//Repeat until convergence | ||
function snapRound(points, edges, useColor) { | ||
function preRound (points, edges, useColor) { | ||
var labels = dedupPoints(points, [], boundPoints(points)) | ||
dedupEdges(edges, labels, useColor) | ||
return !!labels | ||
} | ||
// Repeat until convergence | ||
function snapRound (points, edges, useColor) { | ||
// 1. find edge crossings | ||
var edgeBounds = boundEdges(points, edges) | ||
var crossings = getCrossings(points, edges, edgeBounds) | ||
var crossings = getCrossings(points, edges, edgeBounds) | ||
@@ -331,12 +349,12 @@ // 2. find t-junctions | ||
// 3. cut edges, construct rational points | ||
var ratPoints = cutEdges(points, edges, crossings, tjunctions, useColor) | ||
var ratPoints = cutEdges(points, edges, crossings, tjunctions, useColor) | ||
// 4. dedupe verts | ||
var labels = dedupPoints(points, ratPoints, vertBounds) | ||
var labels = dedupPoints(points, ratPoints, vertBounds) | ||
// 6. dedupe edges | ||
// 5. dedupe edges | ||
dedupEdges(edges, labels, useColor) | ||
// 5. check termination | ||
if(!labels) { | ||
// 6. check termination | ||
if (!labels) { | ||
return (crossings.length > 0 || tjunctions.length > 0) | ||
@@ -349,12 +367,10 @@ } | ||
//Main loop, runs PSLG clean up until completion | ||
function cleanPSLG(points, edges, colors) { | ||
var modified = false | ||
//If using colors, augment edges with color data | ||
// Main loop, runs PSLG clean up until completion | ||
function cleanPSLG (points, edges, colors) { | ||
// If using colors, augment edges with color data | ||
var prevEdges | ||
if(colors) { | ||
if (colors) { | ||
prevEdges = edges | ||
var augEdges = new Array(edges.length) | ||
for(var i=0; i<edges.length; ++i) { | ||
for (var i = 0; i < edges.length; ++i) { | ||
var e = edges[i] | ||
@@ -366,12 +382,15 @@ augEdges[i] = [e[0], e[1], colors[i]] | ||
//Run snap rounding until convergence | ||
while(snapRound(points, edges, !!colors)) { | ||
// First round: remove duplicate edges and points | ||
var modified = preRound(points, edges, !!colors) | ||
// Run snap rounding until convergence | ||
while (snapRound(points, edges, !!colors)) { | ||
modified = true | ||
} | ||
//Strip color tags | ||
if(!!colors && modified) { | ||
// Strip color tags | ||
if (!!colors && modified) { | ||
prevEdges.length = 0 | ||
colors.length = 0 | ||
for(var i=0; i<edges.length; ++i) { | ||
for (var i = 0; i < edges.length; ++i) { | ||
var e = edges[i] | ||
@@ -378,0 +397,0 @@ prevEdges.push([e[0], e[1]]) |
'use strict' | ||
//TODO: Move this to a separate module | ||
module.exports = solveIntersection | ||
@@ -15,9 +13,7 @@ | ||
var toFloat = require('big-rat/to-float') | ||
function ratPerp(a, b) { | ||
function ratPerp (a, b) { | ||
return ratSub(ratMul(a[0], b[1]), ratMul(a[1], b[0])) | ||
} | ||
//Solve for intersection | ||
// Solve for intersection | ||
// x = a + t (b-a) | ||
@@ -29,3 +25,3 @@ // (x - c) ^ (d-c) = 0 | ||
function solveIntersection(a, b, c, d) { | ||
function solveIntersection (a, b, c, d) { | ||
var ba = rvSub(b, a) | ||
@@ -36,3 +32,3 @@ var dc = rvSub(d, c) | ||
if(ratSign(baXdc) === 0) { | ||
if (ratSign(baXdc) === 0) { | ||
return null | ||
@@ -45,4 +41,6 @@ } | ||
var t = ratDiv(dcXac, baXdc) | ||
var s = rvMuls(ba, t) | ||
var r = rvAdd(a, s) | ||
return rvAdd(a, rvMuls(ba, t)) | ||
return r | ||
} |
{ | ||
"name": "clean-pslg", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Remove self intersections, t-junctions and duplicate edges/vertices from a planar straight line graph", | ||
@@ -11,7 +11,6 @@ "main": "clean-pslg.js", | ||
"dependencies": { | ||
"big-rat": "^1.0.1", | ||
"big-rat": "^1.0.3", | ||
"box-intersect": "^1.0.1", | ||
"compare-cell": "^1.0.0", | ||
"nextafter": "^1.0.0", | ||
"rat-vec": "^1.1.0", | ||
"rat-vec": "^1.1.1", | ||
"robust-segment-intersect": "^1.0.1", | ||
@@ -18,0 +17,0 @@ "union-find": "^1.0.2", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7
723
381072
15
- Removedcompare-cell@^1.0.0
- Removedcompare-cell@1.0.0(transitive)
Updatedbig-rat@^1.0.3
Updatedrat-vec@^1.1.1