| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- import {object} from "./feature.js";
- import stitch from "./stitch.js";
- function planarRingArea(ring) {
- var i = -1, n = ring.length, a, b = ring[n - 1], area = 0;
- while (++i < n) a = b, b = ring[i], area += a[0] * b[1] - a[1] * b[0];
- return Math.abs(area); // Note: doubled area!
- }
- export default function(topology) {
- return object(topology, mergeArcs.apply(this, arguments));
- }
- export function mergeArcs(topology, objects) {
- var polygonsByArc = {},
- polygons = [],
- groups = [];
- objects.forEach(geometry);
- function geometry(o) {
- switch (o.type) {
- case "GeometryCollection": o.geometries.forEach(geometry); break;
- case "Polygon": extract(o.arcs); break;
- case "MultiPolygon": o.arcs.forEach(extract); break;
- }
- }
- function extract(polygon) {
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
- });
- });
- polygons.push(polygon);
- }
- function area(ring) {
- return planarRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]);
- }
- polygons.forEach(function(polygon) {
- if (!polygon._) {
- var group = [],
- neighbors = [polygon];
- polygon._ = 1;
- groups.push(group);
- while (polygon = neighbors.pop()) {
- group.push(polygon);
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
- if (!polygon._) {
- polygon._ = 1;
- neighbors.push(polygon);
- }
- });
- });
- });
- }
- }
- });
- polygons.forEach(function(polygon) {
- delete polygon._;
- });
- return {
- type: "MultiPolygon",
- arcs: groups.map(function(polygons) {
- var arcs = [], n;
- // Extract the exterior (unique) arcs.
- polygons.forEach(function(polygon) {
- polygon.forEach(function(ring) {
- ring.forEach(function(arc) {
- if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
- arcs.push(arc);
- }
- });
- });
- });
- // Stitch the arcs into one or more rings.
- arcs = stitch(topology, arcs);
- // If more than one ring is returned,
- // at most one of these rings can be the exterior;
- // choose the one with the greatest absolute area.
- if ((n = arcs.length) > 1) {
- for (var i = 1, k = area(arcs[0]), ki, t; i < n; ++i) {
- if ((ki = area(arcs[i])) > k) {
- t = arcs[0], arcs[0] = arcs[i], arcs[i] = t, k = ki;
- }
- }
- }
- return arcs;
- }).filter(function(arcs) {
- return arcs.length > 0;
- })
- };
- }
|