| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838 | // https://github.com/topojson/topojson-server v3.0.1 Copyright 2019 Mike Bostock(function (global, factory) {typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :typeof define === 'function' && define.amd ? define(['exports'], factory) :(global = global || self, factory(global.topojson = global.topojson || {}));}(this, function (exports) { 'use strict';var hasOwnProperty = Object.prototype.hasOwnProperty;// Computes the bounding box of the specified hash of GeoJSON objects.function bounds(objects) {  var x0 = Infinity,      y0 = Infinity,      x1 = -Infinity,      y1 = -Infinity;  function boundGeometry(geometry) {    if (geometry != null && hasOwnProperty.call(boundGeometryType, geometry.type)) boundGeometryType[geometry.type](geometry);  }  var boundGeometryType = {    GeometryCollection: function(o) { o.geometries.forEach(boundGeometry); },    Point: function(o) { boundPoint(o.coordinates); },    MultiPoint: function(o) { o.coordinates.forEach(boundPoint); },    LineString: function(o) { boundLine(o.arcs); },    MultiLineString: function(o) { o.arcs.forEach(boundLine); },    Polygon: function(o) { o.arcs.forEach(boundLine); },    MultiPolygon: function(o) { o.arcs.forEach(boundMultiLine); }  };  function boundPoint(coordinates) {    var x = coordinates[0],        y = coordinates[1];    if (x < x0) x0 = x;    if (x > x1) x1 = x;    if (y < y0) y0 = y;    if (y > y1) y1 = y;  }  function boundLine(coordinates) {    coordinates.forEach(boundPoint);  }  function boundMultiLine(coordinates) {    coordinates.forEach(boundLine);  }  for (var key in objects) {    boundGeometry(objects[key]);  }  return x1 >= x0 && y1 >= y0 ? [x0, y0, x1, y1] : undefined;}function hashset(size, hash, equal, type, empty) {  if (arguments.length === 3) {    type = Array;    empty = null;  }  var store = new type(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),      mask = size - 1;  for (var i = 0; i < size; ++i) {    store[i] = empty;  }  function add(value) {    var index = hash(value) & mask,        match = store[index],        collisions = 0;    while (match != empty) {      if (equal(match, value)) return true;      if (++collisions >= size) throw new Error("full hashset");      match = store[index = (index + 1) & mask];    }    store[index] = value;    return true;  }  function has(value) {    var index = hash(value) & mask,        match = store[index],        collisions = 0;    while (match != empty) {      if (equal(match, value)) return true;      if (++collisions >= size) break;      match = store[index = (index + 1) & mask];    }    return false;  }  function values() {    var values = [];    for (var i = 0, n = store.length; i < n; ++i) {      var match = store[i];      if (match != empty) values.push(match);    }    return values;  }  return {    add: add,    has: has,    values: values  };}function hashmap(size, hash, equal, keyType, keyEmpty, valueType) {  if (arguments.length === 3) {    keyType = valueType = Array;    keyEmpty = null;  }  var keystore = new keyType(size = 1 << Math.max(4, Math.ceil(Math.log(size) / Math.LN2))),      valstore = new valueType(size),      mask = size - 1;  for (var i = 0; i < size; ++i) {    keystore[i] = keyEmpty;  }  function set(key, value) {    var index = hash(key) & mask,        matchKey = keystore[index],        collisions = 0;    while (matchKey != keyEmpty) {      if (equal(matchKey, key)) return valstore[index] = value;      if (++collisions >= size) throw new Error("full hashmap");      matchKey = keystore[index = (index + 1) & mask];    }    keystore[index] = key;    valstore[index] = value;    return value;  }  function maybeSet(key, value) {    var index = hash(key) & mask,        matchKey = keystore[index],        collisions = 0;    while (matchKey != keyEmpty) {      if (equal(matchKey, key)) return valstore[index];      if (++collisions >= size) throw new Error("full hashmap");      matchKey = keystore[index = (index + 1) & mask];    }    keystore[index] = key;    valstore[index] = value;    return value;  }  function get(key, missingValue) {    var index = hash(key) & mask,        matchKey = keystore[index],        collisions = 0;    while (matchKey != keyEmpty) {      if (equal(matchKey, key)) return valstore[index];      if (++collisions >= size) break;      matchKey = keystore[index = (index + 1) & mask];    }    return missingValue;  }  function keys() {    var keys = [];    for (var i = 0, n = keystore.length; i < n; ++i) {      var matchKey = keystore[i];      if (matchKey != keyEmpty) keys.push(matchKey);    }    return keys;  }  return {    set: set,    maybeSet: maybeSet, // set if unset    get: get,    keys: keys  };}function equalPoint(pointA, pointB) {  return pointA[0] === pointB[0] && pointA[1] === pointB[1];}// TODO if quantized, use simpler Int32 hashing?var buffer = new ArrayBuffer(16),    floats = new Float64Array(buffer),    uints = new Uint32Array(buffer);function hashPoint(point) {  floats[0] = point[0];  floats[1] = point[1];  var hash = uints[0] ^ uints[1];  hash = hash << 5 ^ hash >> 7 ^ uints[2] ^ uints[3];  return hash & 0x7fffffff;}// 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.function join(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;}// Given an extracted (pre-)topology, cuts (or rotates) arcs so that all shared// point sequences are identified. The topology can then be subsequently deduped// to remove exact duplicate arcs.function cut(topology) {  var junctions = join(topology),      coordinates = topology.coordinates,      lines = topology.lines,      rings = topology.rings,      next,      i, n;  for (i = 0, n = lines.length; i < n; ++i) {    var line = lines[i],        lineMid = line[0],        lineEnd = line[1];    while (++lineMid < lineEnd) {      if (junctions.has(coordinates[lineMid])) {        next = {0: lineMid, 1: line[1]};        line[1] = lineMid;        line = line.next = next;      }    }  }  for (i = 0, n = rings.length; i < n; ++i) {    var ring = rings[i],        ringStart = ring[0],        ringMid = ringStart,        ringEnd = ring[1],        ringFixed = junctions.has(coordinates[ringStart]);    while (++ringMid < ringEnd) {      if (junctions.has(coordinates[ringMid])) {        if (ringFixed) {          next = {0: ringMid, 1: ring[1]};          ring[1] = ringMid;          ring = ring.next = next;        } else { // For the first junction, we can rotate rather than cut.          rotateArray(coordinates, ringStart, ringEnd, ringEnd - ringMid);          coordinates[ringEnd] = coordinates[ringStart];          ringFixed = true;          ringMid = ringStart; // restart; we may have skipped junctions        }      }    }  }  return topology;}function rotateArray(array, start, end, offset) {  reverse(array, start, end);  reverse(array, start, start + offset);  reverse(array, start + offset, end);}function reverse(array, start, end) {  for (var mid = start + ((end-- - start) >> 1), t; start < mid; ++start, --end) {    t = array[start], array[start] = array[end], array[end] = t;  }}// Given a cut topology, combines duplicate arcs.function dedup(topology) {  var coordinates = topology.coordinates,      lines = topology.lines, line,      rings = topology.rings, ring,      arcCount = lines.length + rings.length,      i, n;  delete topology.lines;  delete topology.rings;  // Count the number of (non-unique) arcs to initialize the hashmap safely.  for (i = 0, n = lines.length; i < n; ++i) {    line = lines[i]; while (line = line.next) ++arcCount;  }  for (i = 0, n = rings.length; i < n; ++i) {    ring = rings[i]; while (ring = ring.next) ++arcCount;  }  var arcsByEnd = hashmap(arcCount * 2 * 1.4, hashPoint, equalPoint),      arcs = topology.arcs = [];  for (i = 0, n = lines.length; i < n; ++i) {    line = lines[i];    do {      dedupLine(line);    } while (line = line.next);  }  for (i = 0, n = rings.length; i < n; ++i) {    ring = rings[i];    if (ring.next) { // arc is no longer closed      do {        dedupLine(ring);      } while (ring = ring.next);    } else {      dedupRing(ring);    }  }  function dedupLine(arc) {    var startPoint,        endPoint,        startArcs, startArc,        endArcs, endArc,        i, n;    // Does this arc match an existing arc in order?    if (startArcs = arcsByEnd.get(startPoint = coordinates[arc[0]])) {      for (i = 0, n = startArcs.length; i < n; ++i) {        startArc = startArcs[i];        if (equalLine(startArc, arc)) {          arc[0] = startArc[0];          arc[1] = startArc[1];          return;        }      }    }    // Does this arc match an existing arc in reverse order?    if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[1]])) {      for (i = 0, n = endArcs.length; i < n; ++i) {        endArc = endArcs[i];        if (reverseEqualLine(endArc, arc)) {          arc[1] = endArc[0];          arc[0] = endArc[1];          return;        }      }    }    if (startArcs) startArcs.push(arc); else arcsByEnd.set(startPoint, [arc]);    if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);    arcs.push(arc);  }  function dedupRing(arc) {    var endPoint,        endArcs,        endArc,        i, n;    // Does this arc match an existing line in order, or reverse order?    // Rings are closed, so their start point and end point is the same.    if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0]])) {      for (i = 0, n = endArcs.length; i < n; ++i) {        endArc = endArcs[i];        if (equalRing(endArc, arc)) {          arc[0] = endArc[0];          arc[1] = endArc[1];          return;        }        if (reverseEqualRing(endArc, arc)) {          arc[0] = endArc[1];          arc[1] = endArc[0];          return;        }      }    }    // Otherwise, does this arc match an existing ring in order, or reverse order?    if (endArcs = arcsByEnd.get(endPoint = coordinates[arc[0] + findMinimumOffset(arc)])) {      for (i = 0, n = endArcs.length; i < n; ++i) {        endArc = endArcs[i];        if (equalRing(endArc, arc)) {          arc[0] = endArc[0];          arc[1] = endArc[1];          return;        }        if (reverseEqualRing(endArc, arc)) {          arc[0] = endArc[1];          arc[1] = endArc[0];          return;        }      }    }    if (endArcs) endArcs.push(arc); else arcsByEnd.set(endPoint, [arc]);    arcs.push(arc);  }  function equalLine(arcA, arcB) {    var ia = arcA[0], ib = arcB[0],        ja = arcA[1], jb = arcB[1];    if (ia - ja !== ib - jb) return false;    for (; ia <= ja; ++ia, ++ib) if (!equalPoint(coordinates[ia], coordinates[ib])) return false;    return true;  }  function reverseEqualLine(arcA, arcB) {    var ia = arcA[0], ib = arcB[0],        ja = arcA[1], jb = arcB[1];    if (ia - ja !== ib - jb) return false;    for (; ia <= ja; ++ia, --jb) if (!equalPoint(coordinates[ia], coordinates[jb])) return false;    return true;  }  function equalRing(arcA, arcB) {    var ia = arcA[0], ib = arcB[0],        ja = arcA[1], jb = arcB[1],        n = ja - ia;    if (n !== jb - ib) return false;    var ka = findMinimumOffset(arcA),        kb = findMinimumOffset(arcB);    for (var i = 0; i < n; ++i) {      if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[ib + (i + kb) % n])) return false;    }    return true;  }  function reverseEqualRing(arcA, arcB) {    var ia = arcA[0], ib = arcB[0],        ja = arcA[1], jb = arcB[1],        n = ja - ia;    if (n !== jb - ib) return false;    var ka = findMinimumOffset(arcA),        kb = n - findMinimumOffset(arcB);    for (var i = 0; i < n; ++i) {      if (!equalPoint(coordinates[ia + (i + ka) % n], coordinates[jb - (i + kb) % n])) return false;    }    return true;  }  // Rings are rotated to a consistent, but arbitrary, start point.  // This is necessary to detect when a ring and a rotated copy are dupes.  function findMinimumOffset(arc) {    var start = arc[0],        end = arc[1],        mid = start,        minimum = mid,        minimumPoint = coordinates[mid];    while (++mid < end) {      var point = coordinates[mid];      if (point[0] < minimumPoint[0] || point[0] === minimumPoint[0] && point[1] < minimumPoint[1]) {        minimum = mid;        minimumPoint = point;      }    }    return minimum - start;  }  return topology;}// Given an array of arcs in absolute (but already quantized!) coordinates,// converts to fixed-point delta encoding.// This is a destructive operation that modifies the given arcs!function delta(arcs) {  var i = -1,      n = arcs.length;  while (++i < n) {    var arc = arcs[i],        j = 0,        k = 1,        m = arc.length,        point = arc[0],        x0 = point[0],        y0 = point[1],        x1,        y1;    while (++j < m) {      point = arc[j], x1 = point[0], y1 = point[1];      if (x1 !== x0 || y1 !== y0) arc[k++] = [x1 - x0, y1 - y0], x0 = x1, y0 = y1;    }    if (k === 1) arc[k++] = [0, 0]; // Each arc must be an array of two or more positions.    arc.length = k;  }  return arcs;}// Extracts the lines and rings from the specified hash of geometry objects.//// Returns an object with three properties://// * coordinates - shared buffer of [x, y] coordinates// * lines - lines extracted from the hash, of the form [start, end]// * rings - rings extracted from the hash, of the form [start, end]//// For each ring or line, start and end represent inclusive indexes into the// coordinates buffer. For rings (and closed lines), coordinates[start] equals// coordinates[end].//// For each line or polygon geometry in the input hash, including nested// geometries as in geometry collections, the `coordinates` array is replaced// with an equivalent `arcs` array that, for each line (for line string// geometries) or ring (for polygon geometries), points to one of the above// lines or rings.function extract(objects) {  var index = -1,      lines = [],      rings = [],      coordinates = [];  function extractGeometry(geometry) {    if (geometry && hasOwnProperty.call(extractGeometryType, geometry.type)) extractGeometryType[geometry.type](geometry);  }  var extractGeometryType = {    GeometryCollection: function(o) { o.geometries.forEach(extractGeometry); },    LineString: function(o) { o.arcs = extractLine(o.arcs); },    MultiLineString: function(o) { o.arcs = o.arcs.map(extractLine); },    Polygon: function(o) { o.arcs = o.arcs.map(extractRing); },    MultiPolygon: function(o) { o.arcs = o.arcs.map(extractMultiRing); }  };  function extractLine(line) {    for (var i = 0, n = line.length; i < n; ++i) coordinates[++index] = line[i];    var arc = {0: index - n + 1, 1: index};    lines.push(arc);    return arc;  }  function extractRing(ring) {    for (var i = 0, n = ring.length; i < n; ++i) coordinates[++index] = ring[i];    var arc = {0: index - n + 1, 1: index};    rings.push(arc);    return arc;  }  function extractMultiRing(rings) {    return rings.map(extractRing);  }  for (var key in objects) {    extractGeometry(objects[key]);  }  return {    type: "Topology",    coordinates: coordinates,    lines: lines,    rings: rings,    objects: objects  };}// Given a hash of GeoJSON objects, returns a hash of GeoJSON geometry objects.// Any null input geometry objects are represented as {type: null} in the output.// Any feature.{id,properties,bbox} are transferred to the output geometry object.// Each output geometry object is a shallow copy of the input (e.g., properties, coordinates)!function geometry(inputs) {  var outputs = {}, key;  for (key in inputs) outputs[key] = geomifyObject(inputs[key]);  return outputs;}function geomifyObject(input) {  return input == null ? {type: null}      : (input.type === "FeatureCollection" ? geomifyFeatureCollection      : input.type === "Feature" ? geomifyFeature      : geomifyGeometry)(input);}function geomifyFeatureCollection(input) {  var output = {type: "GeometryCollection", geometries: input.features.map(geomifyFeature)};  if (input.bbox != null) output.bbox = input.bbox;  return output;}function geomifyFeature(input) {  var output = geomifyGeometry(input.geometry), key; // eslint-disable-line no-unused-vars  if (input.id != null) output.id = input.id;  if (input.bbox != null) output.bbox = input.bbox;  for (key in input.properties) { output.properties = input.properties; break; }  return output;}function geomifyGeometry(input) {  if (input == null) return {type: null};  var output = input.type === "GeometryCollection" ? {type: "GeometryCollection", geometries: input.geometries.map(geomifyGeometry)}      : input.type === "Point" || input.type === "MultiPoint" ? {type: input.type, coordinates: input.coordinates}      : {type: input.type, arcs: input.coordinates}; // TODO Check for unknown types?  if (input.bbox != null) output.bbox = input.bbox;  return output;}function prequantize(objects, bbox, n) {  var x0 = bbox[0],      y0 = bbox[1],      x1 = bbox[2],      y1 = bbox[3],      kx = x1 - x0 ? (n - 1) / (x1 - x0) : 1,      ky = y1 - y0 ? (n - 1) / (y1 - y0) : 1;  function quantizePoint(input) {    return [Math.round((input[0] - x0) * kx), Math.round((input[1] - y0) * ky)];  }  function quantizePoints(input, m) {    var i = -1,        j = 0,        n = input.length,        output = new Array(n), // pessimistic        pi,        px,        py,        x,        y;    while (++i < n) {      pi = input[i];      x = Math.round((pi[0] - x0) * kx);      y = Math.round((pi[1] - y0) * ky);      if (x !== px || y !== py) output[j++] = [px = x, py = y]; // non-coincident points    }    output.length = j;    while (j < m) j = output.push([output[0][0], output[0][1]]);    return output;  }  function quantizeLine(input) {    return quantizePoints(input, 2);  }  function quantizeRing(input) {    return quantizePoints(input, 4);  }  function quantizePolygon(input) {    return input.map(quantizeRing);  }  function quantizeGeometry(o) {    if (o != null && hasOwnProperty.call(quantizeGeometryType, o.type)) quantizeGeometryType[o.type](o);  }  var quantizeGeometryType = {    GeometryCollection: function(o) { o.geometries.forEach(quantizeGeometry); },    Point: function(o) { o.coordinates = quantizePoint(o.coordinates); },    MultiPoint: function(o) { o.coordinates = o.coordinates.map(quantizePoint); },    LineString: function(o) { o.arcs = quantizeLine(o.arcs); },    MultiLineString: function(o) { o.arcs = o.arcs.map(quantizeLine); },    Polygon: function(o) { o.arcs = quantizePolygon(o.arcs); },    MultiPolygon: function(o) { o.arcs = o.arcs.map(quantizePolygon); }  };  for (var key in objects) {    quantizeGeometry(objects[key]);  }  return {    scale: [1 / kx, 1 / ky],    translate: [x0, y0]  };}// Constructs the TopoJSON Topology for the specified hash of features.// Each object in the specified hash must be a GeoJSON object,// meaning FeatureCollection, a Feature or a geometry object.function topology(objects, quantization) {  var bbox = bounds(objects = geometry(objects)),      transform = quantization > 0 && bbox && prequantize(objects, bbox, quantization),      topology = dedup(cut(extract(objects))),      coordinates = topology.coordinates,      indexByArc = hashmap(topology.arcs.length * 1.4, hashArc, equalArc);  objects = topology.objects; // for garbage collection  topology.bbox = bbox;  topology.arcs = topology.arcs.map(function(arc, i) {    indexByArc.set(arc, i);    return coordinates.slice(arc[0], arc[1] + 1);  });  delete topology.coordinates;  coordinates = null;  function indexGeometry(geometry) {    if (geometry && hasOwnProperty.call(indexGeometryType, geometry.type)) indexGeometryType[geometry.type](geometry);  }  var indexGeometryType = {    GeometryCollection: function(o) { o.geometries.forEach(indexGeometry); },    LineString: function(o) { o.arcs = indexArcs(o.arcs); },    MultiLineString: function(o) { o.arcs = o.arcs.map(indexArcs); },    Polygon: function(o) { o.arcs = o.arcs.map(indexArcs); },    MultiPolygon: function(o) { o.arcs = o.arcs.map(indexMultiArcs); }  };  function indexArcs(arc) {    var indexes = [];    do {      var index = indexByArc.get(arc);      indexes.push(arc[0] < arc[1] ? index : ~index);    } while (arc = arc.next);    return indexes;  }  function indexMultiArcs(arcs) {    return arcs.map(indexArcs);  }  for (var key in objects) {    indexGeometry(objects[key]);  }  if (transform) {    topology.transform = transform;    topology.arcs = delta(topology.arcs);  }  return topology;}function hashArc(arc) {  var i = arc[0], j = arc[1], t;  if (j < i) t = i, i = j, j = t;  return i + 31 * j;}function equalArc(arcA, arcB) {  var ia = arcA[0], ja = arcA[1],      ib = arcB[0], jb = arcB[1], t;  if (ja < ia) t = ia, ia = ja, ja = t;  if (jb < ib) t = ib, ib = jb, jb = t;  return ia === ib && ja === jb;}exports.topology = topology;Object.defineProperty(exports, '__esModule', { value: true });}));
 |