Skip to content

Commit

Permalink
FOLD.filter.addVertexAndSubdivide, FOLD.filter.addEdgeLike, tweak FOL…
Browse files Browse the repository at this point in the history
…D.filter.addEdgeAndSubdivide, FOLD.filter.addEdgeAndSubdivide

* `FOLD.filter.addEdgeAndSubdivide` now uses `FOLD.filter.addVertexAndSubdivide`
  and returns two arrays of edges, for more efficient updating.
  • Loading branch information
edemaine committed Jan 19, 2019
1 parent 14bb95a commit e083d71
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 85 deletions.
140 changes: 88 additions & 52 deletions dist/fold.js
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,55 @@ filter.maybeAddVertex = function(fold, coords, epsilon) {
}
};

filter.addEdgeLike = function(fold, v1, v2, oldEdgeIndex) {
var eNew, k, key, len, ref;
eNew = fold.edges_vertices.length;
ref = filter.keysStartingWith(fold, 'edges_');
for (k = 0, len = ref.length; k < len; k++) {
key = ref[k];
switch (key.slice(6)) {
case 'vertices':
fold.edges_vertices.push([v1, v2]);
break;
case 'edges':
break;
default:
fold[key][eNew] = fold[key][oldEdgeIndex];
}
}
return eNew;
};

filter.addVertexAndSubdivide = function(fold, coords, epsilon) {
var changedEdges, e, i, iNew, k, len, ref, s, u, v;
v = filter.maybeAddVertex(fold, coords, epsilon);
changedEdges = [];
if (v === fold.vertices_coords.length - 1) {
ref = fold.edges_vertices;
for (i = k = 0, len = ref.length; k < len; i = ++k) {
e = ref[i];
if (indexOf.call(e, v) >= 0) {
continue;
}
s = (function() {
var l, len1, results;
results = [];
for (l = 0, len1 = e.length; l < len1; l++) {
u = e[l];
results.push(fold.vertices_coords[u]);
}
return results;
})();
if (geom.pointStrictlyInSegment(coords, s)) {
iNew = filter.addEdgeLike(fold, v, e[1], i);
changedEdges.push(i, iNew);
e[1] = v;
}
}
}
return [v, changedEdges];
};

filter.removeLoopEdges = function(fold) {

/*
Expand Down Expand Up @@ -647,43 +696,28 @@ filter.subdivideCrossingEdges_vertices = function(fold, epsilon, involvingEdgesF
var addEdge, changedEdges, cross, crossI, e, e1, e2, i, i1, i2, k, l, len, len1, len2, len3, m, n, old2new, p, ref, ref1, ref2, ref3, s, s1, s2, u, v, vertices;
changedEdges = [[], []];
addEdge = function(v1, v2, oldEdgeIndex, which) {
var eNew, k, key, len, ref, results;
eNew = fold.edges_vertices.length;
changedEdges[which].push(oldEdgeIndex, fold.edges_vertices.length);
ref = filter.keysStartingWith(fold, 'edges_');
results = [];
for (k = 0, len = ref.length; k < len; k++) {
key = ref[k];
switch (key.slice(6)) {
case 'vertices':
results.push(fold.edges_vertices.push([v1, v2]));
break;
case 'edges':
break;
default:
results.push(fold[key][eNew] = fold[key][oldEdgeIndex]);
}
}
return results;
var eNew;
eNew = filter.addEdgeLike(fold, v1, v2, oldEdgeIndex);
return changedEdges[which].push(oldEdgeIndex, eNew);
};
i = involvingEdgesFrom != null ? involvingEdgesFrom : 0;
while (i < fold.edges_vertices.length) {
e = fold.edges_vertices[i];
s = (function() {
var k, len, results;
results = [];
for (k = 0, len = e.length; k < len; k++) {
u = e[k];
results.push(fold.vertices_coords[u]);
}
return results;
})();
ref = fold.vertices_coords;
for (v = k = 0, len = ref.length; k < len; v = ++k) {
p = ref[v];
if (indexOf.call(e, v) >= 0) {
continue;
}
s = (function() {
var l, len1, results;
results = [];
for (l = 0, len1 = e.length; l < len1; l++) {
u = e[l];
results.push(fold.vertices_coords[u]);
}
return results;
})();
if (geom.pointStrictlyInSegment(p, s)) {
addEdge(v, e[1], i, 0);
e[1] = v;
Expand Down Expand Up @@ -747,9 +781,7 @@ filter.subdivideCrossingEdges_vertices = function(fold, epsilon, involvingEdgesF
results = [];
for (n = 0, len3 = ref3.length; n < len3; n++) {
e = ref3[n];
if (old2new[e] != null) {
results.push(old2new[e]);
}
results.push(old2new[e]);
}
return results;
})();
Expand All @@ -764,9 +796,7 @@ filter.subdivideCrossingEdges_vertices = function(fold, epsilon, involvingEdgesF
results = [];
for (o = 0, len4 = ref4.length; o < len4; o++) {
e = ref4[o];
if (old2new[e] != null) {
results.push(old2new[e]);
}
results.push(old2new[e]);
}
return results;
})();
Expand All @@ -782,37 +812,43 @@ filter.addEdgeAndSubdivide = function(fold, v1, v2, epsilon) {

/*
Add an edge between vertex indices or points `v1` and `v2`, subdivide
as necessary, and return an array of all the subdivided parts of this edge.
If the edge is a loop or a duplicate, the array will be empty.
as necessary, and return two arrays: all the subdivided parts of this edge,
and all the other edges that change.
If the edge is a loop or a duplicate, both arrays will be empty.
*/
var changedEdges1, e, i, k, len, ref;
var changedEdges, changedEdges1, changedEdges2, e, i, iNew, k, len, ref, ref1, ref2, ref3, ref4;
if (v1.length != null) {
v1 = filter.maybeAddVertex(fold, v1, epsilon);
ref = filter.addVertexAndSubdivide(fold, v1, epsilon), v1 = ref[0], changedEdges1 = ref[1];
}
if (v2.length != null) {
v2 = filter.maybeAddVertex(fold, v2, epsilon);
ref1 = filter.addVertexAndSubdivide(fold, v2, epsilon), v2 = ref1[0], changedEdges2 = ref1[1];
}
if (v1 === v2) {
return [];
return [[], []];
}
ref = fold.edges_vertices;
for (i = k = 0, len = ref.length; k < len; i = ++k) {
e = ref[i];
ref2 = fold.edges_vertices;
for (i = k = 0, len = ref2.length; k < len; i = ++k) {
e = ref2[i];
if ((e[0] === v1 && e[1] === v2) || (e[0] === v2 && e[1] === v1)) {
return [];
return [[i], []];
}
}
e = fold.edges_vertices.push([v1, v2]) - 1;
if (e) {
changedEdges1 = filter.subdivideCrossingEdges_vertices(fold, epsilon, e)[0];
if (changedEdges1.length) {
if (indexOf.call(changedEdges1, e) < 0) {
changedEdges1.push(e);
}
return changedEdges1;
iNew = fold.edges_vertices.push([v1, v2]) - 1;
if (iNew) {
changedEdges = filter.subdivideCrossingEdges_vertices(fold, epsilon, iNew);
if (indexOf.call(changedEdges[0], iNew) < 0) {
changedEdges[0].push(iNew);
}
} else {
changedEdges = [[iNew], []];
}
if (changedEdges1 != null) {
(ref3 = changedEdges[1]).push.apply(ref3, changedEdges1);
}
if (changedEdges2 != null) {
(ref4 = changedEdges[1]).push.apply(ref4, changedEdges2);
}
return [e];
return changedEdges;
};

filter.edges_vertices_to_vertices_vertices = function(fold) {
Expand Down
25 changes: 19 additions & 6 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,28 @@ for details.
such a vertex within distance `epsilon`, in which case return the closest
such vertex's index. The new vertex has no new properties except
`vertex_coords`.
* `FOLD.filter.addVertexAndSubdivide(fold, coords, epsilon)`:
Given a FOLD object with 2D `vertices_coords` and `edges_vertices`,
maybe adds a new vertex like `FOLD.filter.maybeAddVertex`, and then
subdivides if necessary (via an efficient use of
`FOLD.filter.subdivideCrossingEdges_vertices`).
* `FOLD.filter.addEdgeLike(fold, v1, v2, oldEdgeIndex)`:
Given a FOLD object with `edges_vertices`, adds a new edge connecting
vertices v1 and v2, and copy all other `edges_...` attributes to be like
the existing edge `oldEdgeIndex`. Returns the new edge index.
* `FOLD.filter.addEdgeAndSubdivide(fold, v1, v2, epsilon)`:
Given a FOLD object with `vertices_coords` and `edges_vertices`,
Given a FOLD object with 2D `vertices_coords` and `edges_vertices`,
adds an edge between vertex indices or points `v1` and `v2`
(calling `FOLD.filter.maybeAddVertex` when they are points),
(calling `FOLD.filter.addVertexAndSubdivide` when they are points),
subdividing if necessary (via an efficient use of
`FOLD.filter.subdivideCrossingEdges_vertices`),
and returns an array of all the subdivided parts of the added edge.
If the edge is a loop or a duplicate, the returned array is empty.
The new edge(s) have no properties except `edges_vertices`.
`FOLD.filter.subdivideCrossingEdges_vertices`).
Returns two arrays: one with the indices of all the subdivided parts of the
added edge, and the other with the indices of all other changed edges.
The new edge(s) have no properties except `edges_vertices`, so the first
array tells you which edges to set the properties of.
If the edge is a loop, the returned arrays are empty.
If the edge is a duplicate, the first array has the old edge index and the
second array is empty.

## FOLD.convert

Expand Down
79 changes: 52 additions & 27 deletions src/filter.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,35 @@ filter.maybeAddVertex = (fold, coords, epsilon) ->
else
fold.vertices_coords.push(coords) - 1

filter.addEdgeLike = (fold, v1, v2, oldEdgeIndex) ->
## Add an edge between v1 and v2, and copy data from old edge.
## Must have `edges_vertices` property.
eNew = fold.edges_vertices.length
for key in filter.keysStartingWith fold, 'edges_'
switch key[6..]
when 'vertices'
fold.edges_vertices.push [v1, v2]
when 'edges'
## Leaving these broken
else
fold[key][eNew] = fold[key][oldEdgeIndex]
eNew

filter.addVertexAndSubdivide = (fold, coords, epsilon) ->
v = filter.maybeAddVertex fold, coords, epsilon
changedEdges = []
if v == fold.vertices_coords.length - 1
## Similar to "Handle overlapping edges" case:
for e, i in fold.edges_vertices
continue if v in e # shouldn't happen
s = (fold.vertices_coords[u] for u in e)
if geom.pointStrictlyInSegment coords, s ## implicit epsilon
#console.log coords, 'in', s
iNew = filter.addEdgeLike fold, v, e[1], i
changedEdges.push i, iNew
e[1] = v
[v, changedEdges]

filter.removeLoopEdges = (fold) ->
###
Remove edges whose endpoints are identical. After collapsing via
Expand Down Expand Up @@ -176,27 +205,18 @@ filter.subdivideCrossingEdges_vertices = (fold, epsilon, involvingEdgesFrom) ->

changedEdges = [[], []]
addEdge = (v1, v2, oldEdgeIndex, which) ->
eNew = fold.edges_vertices.length
#console.log 'adding', oldEdgeIndex, fold.edges_vertices.length, 'to', which
changedEdges[which].push oldEdgeIndex, fold.edges_vertices.length
## Add an edge between v1 and v2, and copy data from old edge
for key in filter.keysStartingWith fold, 'edges_'
switch key[6..]
when 'vertices'
fold.edges_vertices.push [v1, v2]
when 'edges'
## Leaving these broken
else
fold[key][eNew] = fold[key][oldEdgeIndex]
eNew = filter.addEdgeLike fold, v1, v2, oldEdgeIndex
changedEdges[which].push oldEdgeIndex, eNew

## Handle overlapping edges by subdividing edges at any vertices on them.
## We use a while loop instead of a for loop to process newly added edges.
i = involvingEdgesFrom ? 0
while i < fold.edges_vertices.length
e = fold.edges_vertices[i]
s = (fold.vertices_coords[u] for u in e)
for p, v in fold.vertices_coords
continue if v in e
s = (fold.vertices_coords[u] for u in e)
if geom.pointStrictlyInSegment p, s ## implicit epsilon
#console.log p, 'in', s
addEdge v, e[1], i, 0
Expand Down Expand Up @@ -235,10 +255,10 @@ filter.subdivideCrossingEdges_vertices = (fold, epsilon, involvingEdgesFrom) ->

old2new = filter.removeDuplicateEdges_vertices fold
for i in [0, 1]
changedEdges[i] = (old2new[e] for e in changedEdges[i] when old2new[e]?)
changedEdges[i] = (old2new[e] for e in changedEdges[i])
old2new = filter.removeLoopEdges fold
for i in [0, 1]
changedEdges[i] = (old2new[e] for e in changedEdges[i] when old2new[e]?)
changedEdges[i] = (old2new[e] for e in changedEdges[i])

#fold
if involvingEdgesFrom?
Expand All @@ -249,24 +269,29 @@ filter.subdivideCrossingEdges_vertices = (fold, epsilon, involvingEdgesFrom) ->
filter.addEdgeAndSubdivide = (fold, v1, v2, epsilon) ->
###
Add an edge between vertex indices or points `v1` and `v2`, subdivide
as necessary, and return an array of all the subdivided parts of this edge.
If the edge is a loop or a duplicate, the array will be empty.
as necessary, and return two arrays: all the subdivided parts of this edge,
and all the other edges that change.
If the edge is a loop or a duplicate, both arrays will be empty.
###
v1 = filter.maybeAddVertex fold, v1, epsilon if v1.length?
v2 = filter.maybeAddVertex fold, v2, epsilon if v2.length?
if v1.length?
[v1, changedEdges1] = filter.addVertexAndSubdivide fold, v1, epsilon
if v2.length?
[v2, changedEdges2] = filter.addVertexAndSubdivide fold, v2, epsilon
if v1 == v2 ## Ignore loop edges
return []
return [[], []]
for e, i in fold.edges_vertices
if (e[0] == v1 and e[1] == v2) or
(e[0] == v2 and e[1] == v1)
return [] ## Ignore duplicate edges
e = fold.edges_vertices.push([v1, v2]) - 1
if e
[changedEdges1] = filter.subdivideCrossingEdges_vertices(fold, epsilon, e)
if changedEdges1.length
changedEdges1.push e unless e in changedEdges1
return changedEdges1
[e]
return [[i], []] ## Ignore duplicate edges
iNew = fold.edges_vertices.push([v1, v2]) - 1
if iNew
changedEdges = filter.subdivideCrossingEdges_vertices(fold, epsilon, iNew)
changedEdges[0].push iNew unless iNew in changedEdges[0]
else
changedEdges = [[iNew], []]
changedEdges[1].push changedEdges1... if changedEdges1?
changedEdges[1].push changedEdges2... if changedEdges2?
changedEdges

filter.edges_vertices_to_vertices_vertices = (fold) ->
###
Expand Down

0 comments on commit e083d71

Please sign in to comment.