Source: rewind2.js

  1. import { check } from "./helpers/check.js";
  2. /**
  3. * @function rewind2
  4. * @summary Rewind a geoJSON (Mapbox). The function allows to rewind the winding order of a GeoJSON object. The winding order of a polygon is the order in which the vertices are visited by the path that defines the polygon. The winding order of a polygon is significant because it determines the interior of the polygon. The winding order of a polygon is typically either clockwise or counterclockwise.
  5. * @description Adapted from MapBox geojson-rewind code (https://github.com/mapbox/grojson-rewind) under ISC license.
  6. * @param {object|array} data - A GeoJSON FeatureCollection, an array of features, an array of geometries, a single feature or a single geometry.
  7. * @property {boolean} [options.outer = false] - rewind Rings Outer
  8. * @returns {object|array} - A GeoJSON FeatureCollection, an array of features, an array of geometries, a single feature or a single geometry (it depends on what you've set as `data`)
  9. * @example
  10. * geotoolbox.rewind2(*a geojson*)
  11. */
  12. export function rewind2(data, { outer = false } = {}) {
  13. const handle = check(data);
  14. let geo = handle.import(data);
  15. for (let i = 0; i < geo.features.length; i++) {
  16. if (geo.features[i].geometry.type === "Polygon") {
  17. rewindRings(geo.features[i].geometry.coordinates, outer);
  18. } else if (geo.features[i].geometry.type === "MultiPolygon") {
  19. for (let j = 0; j < geo.features[i].geometry.coordinates.length; j++) {
  20. rewindRings(geo.features[i].geometry.coordinates[j], outer);
  21. }
  22. }
  23. }
  24. return handle.export(geo);
  25. }
  26. function rewindRings(rings, outer) {
  27. if (rings.length === 0) return;
  28. rewindRing(rings[0], outer);
  29. for (let i = 1; i < rings.length; i++) {
  30. rewindRing(rings[i], !outer);
  31. }
  32. }
  33. function rewindRing(ring, dir) {
  34. let tArea = 0;
  35. let err = 0;
  36. for (let i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
  37. const k = (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
  38. const m = tArea + k;
  39. err += Math.abs(tArea) >= Math.abs(k) ? tArea - m + k : k - m + tArea;
  40. tArea = m;
  41. }
  42. if (tArea + err >= 0 !== !!dir) ring.reverse();
  43. }