index.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. // http://en.wikipedia.org/wiki/Delaunay_triangulation
  4. // https://github.com/ironwallaby/delaunay
  5. var helpers_1 = require("@turf/helpers");
  6. /**
  7. * Takes a set of {@link Point|points} and creates a
  8. * [Triangulated Irregular Network](http://en.wikipedia.org/wiki/Triangulated_irregular_network),
  9. * or a TIN for short, returned as a collection of Polygons. These are often used
  10. * for developing elevation contour maps or stepped heat visualizations.
  11. *
  12. * If an optional z-value property is provided then it is added as properties called `a`, `b`,
  13. * and `c` representing its value at each of the points that represent the corners of the
  14. * triangle.
  15. *
  16. * @name tin
  17. * @param {FeatureCollection<Point>} points input points
  18. * @param {String} [z] name of the property from which to pull z values
  19. * This is optional: if not given, then there will be no extra data added to the derived triangles.
  20. * @returns {FeatureCollection<Polygon>} TIN output
  21. * @example
  22. * // generate some random point data
  23. * var points = turf.randomPoint(30, {bbox: [50, 30, 70, 50]});
  24. *
  25. * // add a random property to each point between 0 and 9
  26. * for (var i = 0; i < points.features.length; i++) {
  27. * points.features[i].properties.z = ~~(Math.random() * 9);
  28. * }
  29. * var tin = turf.tin(points, 'z');
  30. *
  31. * //addToMap
  32. * var addToMap = [tin, points]
  33. * for (var i = 0; i < tin.features.length; i++) {
  34. * var properties = tin.features[i].properties;
  35. * properties.fill = '#' + properties.a + properties.b + properties.c;
  36. * }
  37. */
  38. function tin(points, z) {
  39. // break down points
  40. var isPointZ = false;
  41. return helpers_1.featureCollection(triangulate(points.features.map(function (p) {
  42. var point = {
  43. x: p.geometry.coordinates[0],
  44. y: p.geometry.coordinates[1],
  45. };
  46. if (z) {
  47. point.z = p.properties[z];
  48. }
  49. else if (p.geometry.coordinates.length === 3) {
  50. isPointZ = true;
  51. point.z = p.geometry.coordinates[2];
  52. }
  53. return point;
  54. })).map(function (triangle) {
  55. var a = [triangle.a.x, triangle.a.y];
  56. var b = [triangle.b.x, triangle.b.y];
  57. var c = [triangle.c.x, triangle.c.y];
  58. var properties = {};
  59. // Add z coordinates to triangle points if user passed
  60. // them in that way otherwise add it as a property.
  61. if (isPointZ) {
  62. a.push(triangle.a.z);
  63. b.push(triangle.b.z);
  64. c.push(triangle.c.z);
  65. }
  66. else {
  67. properties = {
  68. a: triangle.a.z,
  69. b: triangle.b.z,
  70. c: triangle.c.z,
  71. };
  72. }
  73. return helpers_1.polygon([[a, b, c, a]], properties);
  74. }));
  75. }
  76. exports.default = tin;
  77. var Triangle = /** @class */ (function () {
  78. function Triangle(a, b, c) {
  79. this.a = a;
  80. this.b = b;
  81. this.c = c;
  82. var A = b.x - a.x;
  83. var B = b.y - a.y;
  84. var C = c.x - a.x;
  85. var D = c.y - a.y;
  86. var E = A * (a.x + b.x) + B * (a.y + b.y);
  87. var F = C * (a.x + c.x) + D * (a.y + c.y);
  88. var G = 2 * (A * (c.y - b.y) - B * (c.x - b.x));
  89. var dx;
  90. var dy;
  91. // If the points of the triangle are collinear, then just find the
  92. // extremes and use the midpoint as the center of the circumcircle.
  93. this.x = (D * E - B * F) / G;
  94. this.y = (A * F - C * E) / G;
  95. dx = this.x - a.x;
  96. dy = this.y - a.y;
  97. this.r = dx * dx + dy * dy;
  98. }
  99. return Triangle;
  100. }());
  101. function byX(a, b) {
  102. return b.x - a.x;
  103. }
  104. function dedup(edges) {
  105. var j = edges.length;
  106. var a;
  107. var b;
  108. var i;
  109. var m;
  110. var n;
  111. outer: while (j) {
  112. b = edges[--j];
  113. a = edges[--j];
  114. i = j;
  115. while (i) {
  116. n = edges[--i];
  117. m = edges[--i];
  118. if ((a === m && b === n) || (a === n && b === m)) {
  119. edges.splice(j, 2);
  120. edges.splice(i, 2);
  121. j -= 2;
  122. continue outer;
  123. }
  124. }
  125. }
  126. }
  127. function triangulate(vertices) {
  128. // Bail if there aren't enough vertices to form any triangles.
  129. if (vertices.length < 3) {
  130. return [];
  131. }
  132. // Ensure the vertex array is in order of descending X coordinate
  133. // (which is needed to ensure a subquadratic runtime), and then find
  134. // the bounding box around the points.
  135. vertices.sort(byX);
  136. var i = vertices.length - 1;
  137. var xmin = vertices[i].x;
  138. var xmax = vertices[0].x;
  139. var ymin = vertices[i].y;
  140. var ymax = ymin;
  141. var epsilon = 1e-12;
  142. var a;
  143. var b;
  144. var c;
  145. var A;
  146. var B;
  147. var G;
  148. while (i--) {
  149. if (vertices[i].y < ymin) {
  150. ymin = vertices[i].y;
  151. }
  152. if (vertices[i].y > ymax) {
  153. ymax = vertices[i].y;
  154. }
  155. }
  156. // Find a supertriangle, which is a triangle that surrounds all the
  157. // vertices. This is used like something of a sentinel value to remove
  158. // cases in the main algorithm, and is removed before we return any
  159. // results.
  160. // Once found, put it in the "open" list. (The "open" list is for
  161. // triangles who may still need to be considered; the "closed" list is
  162. // for triangles which do not.)
  163. var dx = xmax - xmin;
  164. var dy = ymax - ymin;
  165. var dmax = dx > dy ? dx : dy;
  166. var xmid = (xmax + xmin) * 0.5;
  167. var ymid = (ymax + ymin) * 0.5;
  168. var open = [
  169. new Triangle({
  170. __sentinel: true,
  171. x: xmid - 20 * dmax,
  172. y: ymid - dmax,
  173. }, {
  174. __sentinel: true,
  175. x: xmid,
  176. y: ymid + 20 * dmax,
  177. }, {
  178. __sentinel: true,
  179. x: xmid + 20 * dmax,
  180. y: ymid - dmax,
  181. }),
  182. ];
  183. var closed = [];
  184. var edges = [];
  185. var j;
  186. // Incrementally add each vertex to the mesh.
  187. i = vertices.length;
  188. while (i--) {
  189. // For each open triangle, check to see if the current point is
  190. // inside it's circumcircle. If it is, remove the triangle and add
  191. // it's edges to an edge list.
  192. edges.length = 0;
  193. j = open.length;
  194. while (j--) {
  195. // If this point is to the right of this triangle's circumcircle,
  196. // then this triangle should never get checked again. Remove it
  197. // from the open list, add it to the closed list, and skip.
  198. dx = vertices[i].x - open[j].x;
  199. if (dx > 0 && dx * dx > open[j].r) {
  200. closed.push(open[j]);
  201. open.splice(j, 1);
  202. continue;
  203. }
  204. // If not, skip this triangle.
  205. dy = vertices[i].y - open[j].y;
  206. if (dx * dx + dy * dy > open[j].r) {
  207. continue;
  208. }
  209. // Remove the triangle and add it's edges to the edge list.
  210. edges.push(open[j].a, open[j].b, open[j].b, open[j].c, open[j].c, open[j].a);
  211. open.splice(j, 1);
  212. }
  213. // Remove any doubled edges.
  214. dedup(edges);
  215. // Add a new triangle for each edge.
  216. j = edges.length;
  217. while (j) {
  218. b = edges[--j];
  219. a = edges[--j];
  220. c = vertices[i];
  221. // Avoid adding colinear triangles (which have error-prone
  222. // circumcircles)
  223. A = b.x - a.x;
  224. B = b.y - a.y;
  225. G = 2 * (A * (c.y - b.y) - B * (c.x - b.x));
  226. if (Math.abs(G) > epsilon) {
  227. open.push(new Triangle(a, b, c));
  228. }
  229. }
  230. }
  231. // Copy any remaining open triangles to the closed list, and then
  232. // remove any triangles that share a vertex with the supertriangle.
  233. Array.prototype.push.apply(closed, open);
  234. i = closed.length;
  235. while (i--) {
  236. if (closed[i].a.__sentinel ||
  237. closed[i].b.__sentinel ||
  238. closed[i].c.__sentinel) {
  239. closed.splice(i, 1);
  240. }
  241. }
  242. return closed;
  243. }