| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- import hashset from "./hash/hashset.js";
- import hashmap from "./hash/hashmap.js";
- import equalPoint from "./hash/point-equal.js";
- import hashPoint from "./hash/point-hash.js";
- // Given an extracted (pre-)topology, identifies all of the junctions. These are
- // the points at which arcs (lines or rings) will need to be cut so that each
- // arc is represented uniquely.
- //
- // A junction is a point where at least one arc deviates from another arc going
- // through the same point. For example, consider the point B. If there is a arc
- // through ABC and another arc through CBA, then B is not a junction because in
- // both cases the adjacent point pairs are {A,C}. However, if there is an
- // additional arc ABD, then {A,D} != {A,C}, and thus B becomes a junction.
- //
- // For a closed ring ABCA, the first point A’s adjacent points are the second
- // and last point {B,C}. For a line, the first and last point are always
- // considered junctions, even if the line is closed; this ensures that a closed
- // line is never rotated.
- export default function(topology) {
- var coordinates = topology.coordinates,
- lines = topology.lines,
- rings = topology.rings,
- indexes = index(),
- visitedByIndex = new Int32Array(coordinates.length),
- leftByIndex = new Int32Array(coordinates.length),
- rightByIndex = new Int32Array(coordinates.length),
- junctionByIndex = new Int8Array(coordinates.length),
- junctionCount = 0, // upper bound on number of junctions
- i, n,
- previousIndex,
- currentIndex,
- nextIndex;
- for (i = 0, n = coordinates.length; i < n; ++i) {
- visitedByIndex[i] = leftByIndex[i] = rightByIndex[i] = -1;
- }
- for (i = 0, n = lines.length; i < n; ++i) {
- var line = lines[i],
- lineStart = line[0],
- lineEnd = line[1];
- currentIndex = indexes[lineStart];
- nextIndex = indexes[++lineStart];
- ++junctionCount, junctionByIndex[currentIndex] = 1; // start
- while (++lineStart <= lineEnd) {
- sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[lineStart]);
- }
- ++junctionCount, junctionByIndex[nextIndex] = 1; // end
- }
- for (i = 0, n = coordinates.length; i < n; ++i) {
- visitedByIndex[i] = -1;
- }
- for (i = 0, n = rings.length; i < n; ++i) {
- var ring = rings[i],
- ringStart = ring[0] + 1,
- ringEnd = ring[1];
- previousIndex = indexes[ringEnd - 1];
- currentIndex = indexes[ringStart - 1];
- nextIndex = indexes[ringStart];
- sequence(i, previousIndex, currentIndex, nextIndex);
- while (++ringStart <= ringEnd) {
- sequence(i, previousIndex = currentIndex, currentIndex = nextIndex, nextIndex = indexes[ringStart]);
- }
- }
- function sequence(i, previousIndex, currentIndex, nextIndex) {
- if (visitedByIndex[currentIndex] === i) return; // ignore self-intersection
- visitedByIndex[currentIndex] = i;
- var leftIndex = leftByIndex[currentIndex];
- if (leftIndex >= 0) {
- var rightIndex = rightByIndex[currentIndex];
- if ((leftIndex !== previousIndex || rightIndex !== nextIndex)
- && (leftIndex !== nextIndex || rightIndex !== previousIndex)) {
- ++junctionCount, junctionByIndex[currentIndex] = 1;
- }
- } else {
- leftByIndex[currentIndex] = previousIndex;
- rightByIndex[currentIndex] = nextIndex;
- }
- }
- function index() {
- var indexByPoint = hashmap(coordinates.length * 1.4, hashIndex, equalIndex, Int32Array, -1, Int32Array),
- indexes = new Int32Array(coordinates.length);
- for (var i = 0, n = coordinates.length; i < n; ++i) {
- indexes[i] = indexByPoint.maybeSet(i, i);
- }
- return indexes;
- }
- function hashIndex(i) {
- return hashPoint(coordinates[i]);
- }
- function equalIndex(i, j) {
- return equalPoint(coordinates[i], coordinates[j]);
- }
- visitedByIndex = leftByIndex = rightByIndex = null;
- var junctionByPoint = hashset(junctionCount * 1.4, hashPoint, equalPoint), j;
- // Convert back to a standard hashset by point for caller convenience.
- for (i = 0, n = coordinates.length; i < n; ++i) {
- if (junctionByIndex[j = indexes[i]]) {
- junctionByPoint.add(coordinates[j]);
- }
- }
- return junctionByPoint;
- }
|