polygon-clipping.umd.js 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.polygonClipping = factory());
  5. }(this, (function () { 'use strict';
  6. function _classCallCheck(instance, Constructor) {
  7. if (!(instance instanceof Constructor)) {
  8. throw new TypeError("Cannot call a class as a function");
  9. }
  10. }
  11. function _defineProperties(target, props) {
  12. for (var i = 0; i < props.length; i++) {
  13. var descriptor = props[i];
  14. descriptor.enumerable = descriptor.enumerable || false;
  15. descriptor.configurable = true;
  16. if ("value" in descriptor) descriptor.writable = true;
  17. Object.defineProperty(target, descriptor.key, descriptor);
  18. }
  19. }
  20. function _createClass(Constructor, protoProps, staticProps) {
  21. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  22. if (staticProps) _defineProperties(Constructor, staticProps);
  23. return Constructor;
  24. }
  25. /**
  26. * splaytree v3.1.0
  27. * Fast Splay tree for Node and browser
  28. *
  29. * @author Alexander Milevski <info@w8r.name>
  30. * @license MIT
  31. * @preserve
  32. */
  33. var Node =
  34. /** @class */
  35. function () {
  36. function Node(key, data) {
  37. this.next = null;
  38. this.key = key;
  39. this.data = data;
  40. this.left = null;
  41. this.right = null;
  42. }
  43. return Node;
  44. }();
  45. /* follows "An implementation of top-down splaying"
  46. * by D. Sleator <sleator@cs.cmu.edu> March 1992
  47. */
  48. function DEFAULT_COMPARE(a, b) {
  49. return a > b ? 1 : a < b ? -1 : 0;
  50. }
  51. /**
  52. * Simple top down splay, not requiring i to be in the tree t.
  53. */
  54. function splay(i, t, comparator) {
  55. var N = new Node(null, null);
  56. var l = N;
  57. var r = N;
  58. while (true) {
  59. var cmp = comparator(i, t.key); //if (i < t.key) {
  60. if (cmp < 0) {
  61. if (t.left === null) break; //if (i < t.left.key) {
  62. if (comparator(i, t.left.key) < 0) {
  63. var y = t.left;
  64. /* rotate right */
  65. t.left = y.right;
  66. y.right = t;
  67. t = y;
  68. if (t.left === null) break;
  69. }
  70. r.left = t;
  71. /* link right */
  72. r = t;
  73. t = t.left; //} else if (i > t.key) {
  74. } else if (cmp > 0) {
  75. if (t.right === null) break; //if (i > t.right.key) {
  76. if (comparator(i, t.right.key) > 0) {
  77. var y = t.right;
  78. /* rotate left */
  79. t.right = y.left;
  80. y.left = t;
  81. t = y;
  82. if (t.right === null) break;
  83. }
  84. l.right = t;
  85. /* link left */
  86. l = t;
  87. t = t.right;
  88. } else break;
  89. }
  90. /* assemble */
  91. l.right = t.left;
  92. r.left = t.right;
  93. t.left = N.right;
  94. t.right = N.left;
  95. return t;
  96. }
  97. function insert(i, data, t, comparator) {
  98. var node = new Node(i, data);
  99. if (t === null) {
  100. node.left = node.right = null;
  101. return node;
  102. }
  103. t = splay(i, t, comparator);
  104. var cmp = comparator(i, t.key);
  105. if (cmp < 0) {
  106. node.left = t.left;
  107. node.right = t;
  108. t.left = null;
  109. } else if (cmp >= 0) {
  110. node.right = t.right;
  111. node.left = t;
  112. t.right = null;
  113. }
  114. return node;
  115. }
  116. function split(key, v, comparator) {
  117. var left = null;
  118. var right = null;
  119. if (v) {
  120. v = splay(key, v, comparator);
  121. var cmp = comparator(v.key, key);
  122. if (cmp === 0) {
  123. left = v.left;
  124. right = v.right;
  125. } else if (cmp < 0) {
  126. right = v.right;
  127. v.right = null;
  128. left = v;
  129. } else {
  130. left = v.left;
  131. v.left = null;
  132. right = v;
  133. }
  134. }
  135. return {
  136. left: left,
  137. right: right
  138. };
  139. }
  140. function merge(left, right, comparator) {
  141. if (right === null) return left;
  142. if (left === null) return right;
  143. right = splay(left.key, right, comparator);
  144. right.left = left;
  145. return right;
  146. }
  147. /**
  148. * Prints level of the tree
  149. */
  150. function printRow(root, prefix, isTail, out, printNode) {
  151. if (root) {
  152. out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
  153. var indent = prefix + (isTail ? ' ' : '│ ');
  154. if (root.left) printRow(root.left, indent, false, out, printNode);
  155. if (root.right) printRow(root.right, indent, true, out, printNode);
  156. }
  157. }
  158. var Tree =
  159. /** @class */
  160. function () {
  161. function Tree(comparator) {
  162. if (comparator === void 0) {
  163. comparator = DEFAULT_COMPARE;
  164. }
  165. this._root = null;
  166. this._size = 0;
  167. this._comparator = comparator;
  168. }
  169. /**
  170. * Inserts a key, allows duplicates
  171. */
  172. Tree.prototype.insert = function (key, data) {
  173. this._size++;
  174. return this._root = insert(key, data, this._root, this._comparator);
  175. };
  176. /**
  177. * Adds a key, if it is not present in the tree
  178. */
  179. Tree.prototype.add = function (key, data) {
  180. var node = new Node(key, data);
  181. if (this._root === null) {
  182. node.left = node.right = null;
  183. this._size++;
  184. this._root = node;
  185. }
  186. var comparator = this._comparator;
  187. var t = splay(key, this._root, comparator);
  188. var cmp = comparator(key, t.key);
  189. if (cmp === 0) this._root = t;else {
  190. if (cmp < 0) {
  191. node.left = t.left;
  192. node.right = t;
  193. t.left = null;
  194. } else if (cmp > 0) {
  195. node.right = t.right;
  196. node.left = t;
  197. t.right = null;
  198. }
  199. this._size++;
  200. this._root = node;
  201. }
  202. return this._root;
  203. };
  204. /**
  205. * @param {Key} key
  206. * @return {Node|null}
  207. */
  208. Tree.prototype.remove = function (key) {
  209. this._root = this._remove(key, this._root, this._comparator);
  210. };
  211. /**
  212. * Deletes i from the tree if it's there
  213. */
  214. Tree.prototype._remove = function (i, t, comparator) {
  215. var x;
  216. if (t === null) return null;
  217. t = splay(i, t, comparator);
  218. var cmp = comparator(i, t.key);
  219. if (cmp === 0) {
  220. /* found it */
  221. if (t.left === null) {
  222. x = t.right;
  223. } else {
  224. x = splay(i, t.left, comparator);
  225. x.right = t.right;
  226. }
  227. this._size--;
  228. return x;
  229. }
  230. return t;
  231. /* It wasn't there */
  232. };
  233. /**
  234. * Removes and returns the node with smallest key
  235. */
  236. Tree.prototype.pop = function () {
  237. var node = this._root;
  238. if (node) {
  239. while (node.left) {
  240. node = node.left;
  241. }
  242. this._root = splay(node.key, this._root, this._comparator);
  243. this._root = this._remove(node.key, this._root, this._comparator);
  244. return {
  245. key: node.key,
  246. data: node.data
  247. };
  248. }
  249. return null;
  250. };
  251. /**
  252. * Find without splaying
  253. */
  254. Tree.prototype.findStatic = function (key) {
  255. var current = this._root;
  256. var compare = this._comparator;
  257. while (current) {
  258. var cmp = compare(key, current.key);
  259. if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
  260. }
  261. return null;
  262. };
  263. Tree.prototype.find = function (key) {
  264. if (this._root) {
  265. this._root = splay(key, this._root, this._comparator);
  266. if (this._comparator(key, this._root.key) !== 0) return null;
  267. }
  268. return this._root;
  269. };
  270. Tree.prototype.contains = function (key) {
  271. var current = this._root;
  272. var compare = this._comparator;
  273. while (current) {
  274. var cmp = compare(key, current.key);
  275. if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
  276. }
  277. return false;
  278. };
  279. Tree.prototype.forEach = function (visitor, ctx) {
  280. var current = this._root;
  281. var Q = [];
  282. /* Initialize stack s */
  283. var done = false;
  284. while (!done) {
  285. if (current !== null) {
  286. Q.push(current);
  287. current = current.left;
  288. } else {
  289. if (Q.length !== 0) {
  290. current = Q.pop();
  291. visitor.call(ctx, current);
  292. current = current.right;
  293. } else done = true;
  294. }
  295. }
  296. return this;
  297. };
  298. /**
  299. * Walk key range from `low` to `high`. Stops if `fn` returns a value.
  300. */
  301. Tree.prototype.range = function (low, high, fn, ctx) {
  302. var Q = [];
  303. var compare = this._comparator;
  304. var node = this._root;
  305. var cmp;
  306. while (Q.length !== 0 || node) {
  307. if (node) {
  308. Q.push(node);
  309. node = node.left;
  310. } else {
  311. node = Q.pop();
  312. cmp = compare(node.key, high);
  313. if (cmp > 0) {
  314. break;
  315. } else if (compare(node.key, low) >= 0) {
  316. if (fn.call(ctx, node)) return this; // stop if smth is returned
  317. }
  318. node = node.right;
  319. }
  320. }
  321. return this;
  322. };
  323. /**
  324. * Returns array of keys
  325. */
  326. Tree.prototype.keys = function () {
  327. var keys = [];
  328. this.forEach(function (_a) {
  329. var key = _a.key;
  330. return keys.push(key);
  331. });
  332. return keys;
  333. };
  334. /**
  335. * Returns array of all the data in the nodes
  336. */
  337. Tree.prototype.values = function () {
  338. var values = [];
  339. this.forEach(function (_a) {
  340. var data = _a.data;
  341. return values.push(data);
  342. });
  343. return values;
  344. };
  345. Tree.prototype.min = function () {
  346. if (this._root) return this.minNode(this._root).key;
  347. return null;
  348. };
  349. Tree.prototype.max = function () {
  350. if (this._root) return this.maxNode(this._root).key;
  351. return null;
  352. };
  353. Tree.prototype.minNode = function (t) {
  354. if (t === void 0) {
  355. t = this._root;
  356. }
  357. if (t) while (t.left) {
  358. t = t.left;
  359. }
  360. return t;
  361. };
  362. Tree.prototype.maxNode = function (t) {
  363. if (t === void 0) {
  364. t = this._root;
  365. }
  366. if (t) while (t.right) {
  367. t = t.right;
  368. }
  369. return t;
  370. };
  371. /**
  372. * Returns node at given index
  373. */
  374. Tree.prototype.at = function (index) {
  375. var current = this._root;
  376. var done = false;
  377. var i = 0;
  378. var Q = [];
  379. while (!done) {
  380. if (current) {
  381. Q.push(current);
  382. current = current.left;
  383. } else {
  384. if (Q.length > 0) {
  385. current = Q.pop();
  386. if (i === index) return current;
  387. i++;
  388. current = current.right;
  389. } else done = true;
  390. }
  391. }
  392. return null;
  393. };
  394. Tree.prototype.next = function (d) {
  395. var root = this._root;
  396. var successor = null;
  397. if (d.right) {
  398. successor = d.right;
  399. while (successor.left) {
  400. successor = successor.left;
  401. }
  402. return successor;
  403. }
  404. var comparator = this._comparator;
  405. while (root) {
  406. var cmp = comparator(d.key, root.key);
  407. if (cmp === 0) break;else if (cmp < 0) {
  408. successor = root;
  409. root = root.left;
  410. } else root = root.right;
  411. }
  412. return successor;
  413. };
  414. Tree.prototype.prev = function (d) {
  415. var root = this._root;
  416. var predecessor = null;
  417. if (d.left !== null) {
  418. predecessor = d.left;
  419. while (predecessor.right) {
  420. predecessor = predecessor.right;
  421. }
  422. return predecessor;
  423. }
  424. var comparator = this._comparator;
  425. while (root) {
  426. var cmp = comparator(d.key, root.key);
  427. if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
  428. predecessor = root;
  429. root = root.right;
  430. }
  431. }
  432. return predecessor;
  433. };
  434. Tree.prototype.clear = function () {
  435. this._root = null;
  436. this._size = 0;
  437. return this;
  438. };
  439. Tree.prototype.toList = function () {
  440. return toList(this._root);
  441. };
  442. /**
  443. * Bulk-load items. Both array have to be same size
  444. */
  445. Tree.prototype.load = function (keys, values, presort) {
  446. if (values === void 0) {
  447. values = [];
  448. }
  449. if (presort === void 0) {
  450. presort = false;
  451. }
  452. var size = keys.length;
  453. var comparator = this._comparator; // sort if needed
  454. if (presort) sort(keys, values, 0, size - 1, comparator);
  455. if (this._root === null) {
  456. // empty tree
  457. this._root = loadRecursive(keys, values, 0, size);
  458. this._size = size;
  459. } else {
  460. // that re-builds the whole tree from two in-order traversals
  461. var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
  462. size = this._size + size;
  463. this._root = sortedListToBST({
  464. head: mergedList
  465. }, 0, size);
  466. }
  467. return this;
  468. };
  469. Tree.prototype.isEmpty = function () {
  470. return this._root === null;
  471. };
  472. Object.defineProperty(Tree.prototype, "size", {
  473. get: function get() {
  474. return this._size;
  475. },
  476. enumerable: true,
  477. configurable: true
  478. });
  479. Object.defineProperty(Tree.prototype, "root", {
  480. get: function get() {
  481. return this._root;
  482. },
  483. enumerable: true,
  484. configurable: true
  485. });
  486. Tree.prototype.toString = function (printNode) {
  487. if (printNode === void 0) {
  488. printNode = function printNode(n) {
  489. return String(n.key);
  490. };
  491. }
  492. var out = [];
  493. printRow(this._root, '', true, function (v) {
  494. return out.push(v);
  495. }, printNode);
  496. return out.join('');
  497. };
  498. Tree.prototype.update = function (key, newKey, newData) {
  499. var comparator = this._comparator;
  500. var _a = split(key, this._root, comparator),
  501. left = _a.left,
  502. right = _a.right;
  503. if (comparator(key, newKey) < 0) {
  504. right = insert(newKey, newData, right, comparator);
  505. } else {
  506. left = insert(newKey, newData, left, comparator);
  507. }
  508. this._root = merge(left, right, comparator);
  509. };
  510. Tree.prototype.split = function (key) {
  511. return split(key, this._root, this._comparator);
  512. };
  513. return Tree;
  514. }();
  515. function loadRecursive(keys, values, start, end) {
  516. var size = end - start;
  517. if (size > 0) {
  518. var middle = start + Math.floor(size / 2);
  519. var key = keys[middle];
  520. var data = values[middle];
  521. var node = new Node(key, data);
  522. node.left = loadRecursive(keys, values, start, middle);
  523. node.right = loadRecursive(keys, values, middle + 1, end);
  524. return node;
  525. }
  526. return null;
  527. }
  528. function createList(keys, values) {
  529. var head = new Node(null, null);
  530. var p = head;
  531. for (var i = 0; i < keys.length; i++) {
  532. p = p.next = new Node(keys[i], values[i]);
  533. }
  534. p.next = null;
  535. return head.next;
  536. }
  537. function toList(root) {
  538. var current = root;
  539. var Q = [];
  540. var done = false;
  541. var head = new Node(null, null);
  542. var p = head;
  543. while (!done) {
  544. if (current) {
  545. Q.push(current);
  546. current = current.left;
  547. } else {
  548. if (Q.length > 0) {
  549. current = p = p.next = Q.pop();
  550. current = current.right;
  551. } else done = true;
  552. }
  553. }
  554. p.next = null; // that'll work even if the tree was empty
  555. return head.next;
  556. }
  557. function sortedListToBST(list, start, end) {
  558. var size = end - start;
  559. if (size > 0) {
  560. var middle = start + Math.floor(size / 2);
  561. var left = sortedListToBST(list, start, middle);
  562. var root = list.head;
  563. root.left = left;
  564. list.head = list.head.next;
  565. root.right = sortedListToBST(list, middle + 1, end);
  566. return root;
  567. }
  568. return null;
  569. }
  570. function mergeLists(l1, l2, compare) {
  571. var head = new Node(null, null); // dummy
  572. var p = head;
  573. var p1 = l1;
  574. var p2 = l2;
  575. while (p1 !== null && p2 !== null) {
  576. if (compare(p1.key, p2.key) < 0) {
  577. p.next = p1;
  578. p1 = p1.next;
  579. } else {
  580. p.next = p2;
  581. p2 = p2.next;
  582. }
  583. p = p.next;
  584. }
  585. if (p1 !== null) {
  586. p.next = p1;
  587. } else if (p2 !== null) {
  588. p.next = p2;
  589. }
  590. return head.next;
  591. }
  592. function sort(keys, values, left, right, compare) {
  593. if (left >= right) return;
  594. var pivot = keys[left + right >> 1];
  595. var i = left - 1;
  596. var j = right + 1;
  597. while (true) {
  598. do {
  599. i++;
  600. } while (compare(keys[i], pivot) < 0);
  601. do {
  602. j--;
  603. } while (compare(keys[j], pivot) > 0);
  604. if (i >= j) break;
  605. var tmp = keys[i];
  606. keys[i] = keys[j];
  607. keys[j] = tmp;
  608. tmp = values[i];
  609. values[i] = values[j];
  610. values[j] = tmp;
  611. }
  612. sort(keys, values, left, j, compare);
  613. sort(keys, values, j + 1, right, compare);
  614. }
  615. /**
  616. * A bounding box has the format:
  617. *
  618. * { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
  619. *
  620. */
  621. var isInBbox = function isInBbox(bbox, point) {
  622. return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
  623. };
  624. /* Returns either null, or a bbox (aka an ordered pair of points)
  625. * If there is only one point of overlap, a bbox with identical points
  626. * will be returned */
  627. var getBboxOverlap = function getBboxOverlap(b1, b2) {
  628. // check if the bboxes overlap at all
  629. if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null; // find the middle two X values
  630. var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
  631. var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
  632. var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
  633. var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
  634. return {
  635. ll: {
  636. x: lowerX,
  637. y: lowerY
  638. },
  639. ur: {
  640. x: upperX,
  641. y: upperY
  642. }
  643. };
  644. };
  645. /* Javascript doesn't do integer math. Everything is
  646. * floating point with percision Number.EPSILON.
  647. *
  648. * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
  649. */
  650. var epsilon = Number.EPSILON; // IE Polyfill
  651. if (epsilon === undefined) epsilon = Math.pow(2, -52);
  652. var EPSILON_SQ = epsilon * epsilon;
  653. /* FLP comparator */
  654. var cmp = function cmp(a, b) {
  655. // check if they're both 0
  656. if (-epsilon < a && a < epsilon) {
  657. if (-epsilon < b && b < epsilon) {
  658. return 0;
  659. }
  660. } // check if they're flp equal
  661. var ab = a - b;
  662. if (ab * ab < EPSILON_SQ * a * b) {
  663. return 0;
  664. } // normal comparison
  665. return a < b ? -1 : 1;
  666. };
  667. /**
  668. * This class rounds incoming values sufficiently so that
  669. * floating points problems are, for the most part, avoided.
  670. *
  671. * Incoming points are have their x & y values tested against
  672. * all previously seen x & y values. If either is 'too close'
  673. * to a previously seen value, it's value is 'snapped' to the
  674. * previously seen value.
  675. *
  676. * All points should be rounded by this class before being
  677. * stored in any data structures in the rest of this algorithm.
  678. */
  679. var PtRounder = /*#__PURE__*/function () {
  680. function PtRounder() {
  681. _classCallCheck(this, PtRounder);
  682. this.reset();
  683. }
  684. _createClass(PtRounder, [{
  685. key: "reset",
  686. value: function reset() {
  687. this.xRounder = new CoordRounder();
  688. this.yRounder = new CoordRounder();
  689. }
  690. }, {
  691. key: "round",
  692. value: function round(x, y) {
  693. return {
  694. x: this.xRounder.round(x),
  695. y: this.yRounder.round(y)
  696. };
  697. }
  698. }]);
  699. return PtRounder;
  700. }();
  701. var CoordRounder = /*#__PURE__*/function () {
  702. function CoordRounder() {
  703. _classCallCheck(this, CoordRounder);
  704. this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
  705. this.round(0);
  706. } // Note: this can rounds input values backwards or forwards.
  707. // You might ask, why not restrict this to just rounding
  708. // forwards? Wouldn't that allow left endpoints to always
  709. // remain left endpoints during splitting (never change to
  710. // right). No - it wouldn't, because we snap intersections
  711. // to endpoints (to establish independence from the segment
  712. // angle for t-intersections).
  713. _createClass(CoordRounder, [{
  714. key: "round",
  715. value: function round(coord) {
  716. var node = this.tree.add(coord);
  717. var prevNode = this.tree.prev(node);
  718. if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
  719. this.tree.remove(coord);
  720. return prevNode.key;
  721. }
  722. var nextNode = this.tree.next(node);
  723. if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
  724. this.tree.remove(coord);
  725. return nextNode.key;
  726. }
  727. return coord;
  728. }
  729. }]);
  730. return CoordRounder;
  731. }(); // singleton available by import
  732. var rounder = new PtRounder();
  733. /* Cross Product of two vectors with first point at origin */
  734. var crossProduct = function crossProduct(a, b) {
  735. return a.x * b.y - a.y * b.x;
  736. };
  737. /* Dot Product of two vectors with first point at origin */
  738. var dotProduct = function dotProduct(a, b) {
  739. return a.x * b.x + a.y * b.y;
  740. };
  741. /* Comparator for two vectors with same starting point */
  742. var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
  743. var v1 = {
  744. x: endPt1.x - basePt.x,
  745. y: endPt1.y - basePt.y
  746. };
  747. var v2 = {
  748. x: endPt2.x - basePt.x,
  749. y: endPt2.y - basePt.y
  750. };
  751. var kross = crossProduct(v1, v2);
  752. return cmp(kross, 0);
  753. };
  754. var length = function length(v) {
  755. return Math.sqrt(dotProduct(v, v));
  756. };
  757. /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
  758. var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
  759. var vBase = {
  760. x: pBase.x - pShared.x,
  761. y: pBase.y - pShared.y
  762. };
  763. var vAngle = {
  764. x: pAngle.x - pShared.x,
  765. y: pAngle.y - pShared.y
  766. };
  767. return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
  768. };
  769. /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
  770. var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
  771. var vBase = {
  772. x: pBase.x - pShared.x,
  773. y: pBase.y - pShared.y
  774. };
  775. var vAngle = {
  776. x: pAngle.x - pShared.x,
  777. y: pAngle.y - pShared.y
  778. };
  779. return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
  780. };
  781. /* Get the x coordinate where the given line (defined by a point and vector)
  782. * crosses the horizontal line with the given y coordiante.
  783. * In the case of parrallel lines (including overlapping ones) returns null. */
  784. var horizontalIntersection = function horizontalIntersection(pt, v, y) {
  785. if (v.y === 0) return null;
  786. return {
  787. x: pt.x + v.x / v.y * (y - pt.y),
  788. y: y
  789. };
  790. };
  791. /* Get the y coordinate where the given line (defined by a point and vector)
  792. * crosses the vertical line with the given x coordiante.
  793. * In the case of parrallel lines (including overlapping ones) returns null. */
  794. var verticalIntersection = function verticalIntersection(pt, v, x) {
  795. if (v.x === 0) return null;
  796. return {
  797. x: x,
  798. y: pt.y + v.y / v.x * (x - pt.x)
  799. };
  800. };
  801. /* Get the intersection of two lines, each defined by a base point and a vector.
  802. * In the case of parrallel lines (including overlapping ones) returns null. */
  803. var intersection = function intersection(pt1, v1, pt2, v2) {
  804. // take some shortcuts for vertical and horizontal lines
  805. // this also ensures we don't calculate an intersection and then discover
  806. // it's actually outside the bounding box of the line
  807. if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
  808. if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
  809. if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
  810. if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
  811. // This algorithm is based on Schneider and Eberly.
  812. // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
  813. var kross = crossProduct(v1, v2);
  814. if (kross == 0) return null;
  815. var ve = {
  816. x: pt2.x - pt1.x,
  817. y: pt2.y - pt1.y
  818. };
  819. var d1 = crossProduct(ve, v1) / kross;
  820. var d2 = crossProduct(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
  821. var x1 = pt1.x + d2 * v1.x,
  822. x2 = pt2.x + d1 * v2.x;
  823. var y1 = pt1.y + d2 * v1.y,
  824. y2 = pt2.y + d1 * v2.y;
  825. var x = (x1 + x2) / 2;
  826. var y = (y1 + y2) / 2;
  827. return {
  828. x: x,
  829. y: y
  830. };
  831. };
  832. var SweepEvent = /*#__PURE__*/function () {
  833. _createClass(SweepEvent, null, [{
  834. key: "compare",
  835. // for ordering sweep events in the sweep event queue
  836. value: function compare(a, b) {
  837. // favor event with a point that the sweep line hits first
  838. var ptCmp = SweepEvent.comparePoints(a.point, b.point);
  839. if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
  840. if (a.point !== b.point) a.link(b); // favor right events over left
  841. if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
  842. // ordering of this case is the same as for their segments
  843. return Segment.compare(a.segment, b.segment);
  844. } // for ordering points in sweep line order
  845. }, {
  846. key: "comparePoints",
  847. value: function comparePoints(aPt, bPt) {
  848. if (aPt.x < bPt.x) return -1;
  849. if (aPt.x > bPt.x) return 1;
  850. if (aPt.y < bPt.y) return -1;
  851. if (aPt.y > bPt.y) return 1;
  852. return 0;
  853. } // Warning: 'point' input will be modified and re-used (for performance)
  854. }]);
  855. function SweepEvent(point, isLeft) {
  856. _classCallCheck(this, SweepEvent);
  857. if (point.events === undefined) point.events = [this];else point.events.push(this);
  858. this.point = point;
  859. this.isLeft = isLeft; // this.segment, this.otherSE set by factory
  860. }
  861. _createClass(SweepEvent, [{
  862. key: "link",
  863. value: function link(other) {
  864. if (other.point === this.point) {
  865. throw new Error('Tried to link already linked events');
  866. }
  867. var otherEvents = other.point.events;
  868. for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
  869. var evt = otherEvents[i];
  870. this.point.events.push(evt);
  871. evt.point = this.point;
  872. }
  873. this.checkForConsuming();
  874. }
  875. /* Do a pass over our linked events and check to see if any pair
  876. * of segments match, and should be consumed. */
  877. }, {
  878. key: "checkForConsuming",
  879. value: function checkForConsuming() {
  880. // FIXME: The loops in this method run O(n^2) => no good.
  881. // Maintain little ordered sweep event trees?
  882. // Can we maintaining an ordering that avoids the need
  883. // for the re-sorting with getLeftmostComparator in geom-out?
  884. // Compare each pair of events to see if other events also match
  885. var numEvents = this.point.events.length;
  886. for (var i = 0; i < numEvents; i++) {
  887. var evt1 = this.point.events[i];
  888. if (evt1.segment.consumedBy !== undefined) continue;
  889. for (var j = i + 1; j < numEvents; j++) {
  890. var evt2 = this.point.events[j];
  891. if (evt2.consumedBy !== undefined) continue;
  892. if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
  893. evt1.segment.consume(evt2.segment);
  894. }
  895. }
  896. }
  897. }, {
  898. key: "getAvailableLinkedEvents",
  899. value: function getAvailableLinkedEvents() {
  900. // point.events is always of length 2 or greater
  901. var events = [];
  902. for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
  903. var evt = this.point.events[i];
  904. if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
  905. events.push(evt);
  906. }
  907. }
  908. return events;
  909. }
  910. /**
  911. * Returns a comparator function for sorting linked events that will
  912. * favor the event that will give us the smallest left-side angle.
  913. * All ring construction starts as low as possible heading to the right,
  914. * so by always turning left as sharp as possible we'll get polygons
  915. * without uncessary loops & holes.
  916. *
  917. * The comparator function has a compute cache such that it avoids
  918. * re-computing already-computed values.
  919. */
  920. }, {
  921. key: "getLeftmostComparator",
  922. value: function getLeftmostComparator(baseEvent) {
  923. var _this = this;
  924. var cache = new Map();
  925. var fillCache = function fillCache(linkedEvent) {
  926. var nextEvent = linkedEvent.otherSE;
  927. cache.set(linkedEvent, {
  928. sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
  929. cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
  930. });
  931. };
  932. return function (a, b) {
  933. if (!cache.has(a)) fillCache(a);
  934. if (!cache.has(b)) fillCache(b);
  935. var _cache$get = cache.get(a),
  936. asine = _cache$get.sine,
  937. acosine = _cache$get.cosine;
  938. var _cache$get2 = cache.get(b),
  939. bsine = _cache$get2.sine,
  940. bcosine = _cache$get2.cosine; // both on or above x-axis
  941. if (asine >= 0 && bsine >= 0) {
  942. if (acosine < bcosine) return 1;
  943. if (acosine > bcosine) return -1;
  944. return 0;
  945. } // both below x-axis
  946. if (asine < 0 && bsine < 0) {
  947. if (acosine < bcosine) return -1;
  948. if (acosine > bcosine) return 1;
  949. return 0;
  950. } // one above x-axis, one below
  951. if (bsine < asine) return -1;
  952. if (bsine > asine) return 1;
  953. return 0;
  954. };
  955. }
  956. }]);
  957. return SweepEvent;
  958. }();
  959. // segments and sweep events when all else is identical
  960. var segmentId = 0;
  961. var Segment = /*#__PURE__*/function () {
  962. _createClass(Segment, null, [{
  963. key: "compare",
  964. /* This compare() function is for ordering segments in the sweep
  965. * line tree, and does so according to the following criteria:
  966. *
  967. * Consider the vertical line that lies an infinestimal step to the
  968. * right of the right-more of the two left endpoints of the input
  969. * segments. Imagine slowly moving a point up from negative infinity
  970. * in the increasing y direction. Which of the two segments will that
  971. * point intersect first? That segment comes 'before' the other one.
  972. *
  973. * If neither segment would be intersected by such a line, (if one
  974. * or more of the segments are vertical) then the line to be considered
  975. * is directly on the right-more of the two left inputs.
  976. */
  977. value: function compare(a, b) {
  978. var alx = a.leftSE.point.x;
  979. var blx = b.leftSE.point.x;
  980. var arx = a.rightSE.point.x;
  981. var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
  982. if (brx < alx) return 1;
  983. if (arx < blx) return -1;
  984. var aly = a.leftSE.point.y;
  985. var bly = b.leftSE.point.y;
  986. var ary = a.rightSE.point.y;
  987. var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
  988. if (alx < blx) {
  989. // are the two segments in the same horizontal plane?
  990. if (bly < aly && bly < ary) return 1;
  991. if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
  992. var aCmpBLeft = a.comparePoint(b.leftSE.point);
  993. if (aCmpBLeft < 0) return 1;
  994. if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
  995. var bCmpARight = b.comparePoint(a.rightSE.point);
  996. if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
  997. // left endpoint to be first (arbitrary?)
  998. return -1;
  999. } // is left endpoint of segment A the right-more?
  1000. if (alx > blx) {
  1001. if (aly < bly && aly < bry) return -1;
  1002. if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
  1003. var bCmpALeft = b.comparePoint(a.leftSE.point);
  1004. if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
  1005. var aCmpBRight = a.comparePoint(b.rightSE.point);
  1006. if (aCmpBRight < 0) return 1;
  1007. if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
  1008. // left endpoint to be first (arbitrary?)
  1009. return 1;
  1010. } // if we get here, the two left endpoints are in the same
  1011. // vertical plane, ie alx === blx
  1012. // consider the lower left-endpoint to come first
  1013. if (aly < bly) return -1;
  1014. if (aly > bly) return 1; // left endpoints are identical
  1015. // check for colinearity by using the left-more right endpoint
  1016. // is the A right endpoint more left-more?
  1017. if (arx < brx) {
  1018. var _bCmpARight = b.comparePoint(a.rightSE.point);
  1019. if (_bCmpARight !== 0) return _bCmpARight;
  1020. } // is the B right endpoint more left-more?
  1021. if (arx > brx) {
  1022. var _aCmpBRight = a.comparePoint(b.rightSE.point);
  1023. if (_aCmpBRight < 0) return 1;
  1024. if (_aCmpBRight > 0) return -1;
  1025. }
  1026. if (arx !== brx) {
  1027. // are these two [almost] vertical segments with opposite orientation?
  1028. // if so, the one with the lower right endpoint comes first
  1029. var ay = ary - aly;
  1030. var ax = arx - alx;
  1031. var by = bry - bly;
  1032. var bx = brx - blx;
  1033. if (ay > ax && by < bx) return 1;
  1034. if (ay < ax && by > bx) return -1;
  1035. } // we have colinear segments with matching orientation
  1036. // consider the one with more left-more right endpoint to be first
  1037. if (arx > brx) return 1;
  1038. if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
  1039. // vertical plane, ie arx === brx
  1040. // consider the lower right-endpoint to come first
  1041. if (ary < bry) return -1;
  1042. if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
  1043. // fall back on creation order as consistent tie-breaker
  1044. if (a.id < b.id) return -1;
  1045. if (a.id > b.id) return 1; // identical segment, ie a === b
  1046. return 0;
  1047. }
  1048. /* Warning: a reference to ringWindings input will be stored,
  1049. * and possibly will be later modified */
  1050. }]);
  1051. function Segment(leftSE, rightSE, rings, windings) {
  1052. _classCallCheck(this, Segment);
  1053. this.id = ++segmentId;
  1054. this.leftSE = leftSE;
  1055. leftSE.segment = this;
  1056. leftSE.otherSE = rightSE;
  1057. this.rightSE = rightSE;
  1058. rightSE.segment = this;
  1059. rightSE.otherSE = leftSE;
  1060. this.rings = rings;
  1061. this.windings = windings; // left unset for performance, set later in algorithm
  1062. // this.ringOut, this.consumedBy, this.prev
  1063. }
  1064. _createClass(Segment, [{
  1065. key: "replaceRightSE",
  1066. /* When a segment is split, the rightSE is replaced with a new sweep event */
  1067. value: function replaceRightSE(newRightSE) {
  1068. this.rightSE = newRightSE;
  1069. this.rightSE.segment = this;
  1070. this.rightSE.otherSE = this.leftSE;
  1071. this.leftSE.otherSE = this.rightSE;
  1072. }
  1073. }, {
  1074. key: "bbox",
  1075. value: function bbox() {
  1076. var y1 = this.leftSE.point.y;
  1077. var y2 = this.rightSE.point.y;
  1078. return {
  1079. ll: {
  1080. x: this.leftSE.point.x,
  1081. y: y1 < y2 ? y1 : y2
  1082. },
  1083. ur: {
  1084. x: this.rightSE.point.x,
  1085. y: y1 > y2 ? y1 : y2
  1086. }
  1087. };
  1088. }
  1089. /* A vector from the left point to the right */
  1090. }, {
  1091. key: "vector",
  1092. value: function vector() {
  1093. return {
  1094. x: this.rightSE.point.x - this.leftSE.point.x,
  1095. y: this.rightSE.point.y - this.leftSE.point.y
  1096. };
  1097. }
  1098. }, {
  1099. key: "isAnEndpoint",
  1100. value: function isAnEndpoint(pt) {
  1101. return pt.x === this.leftSE.point.x && pt.y === this.leftSE.point.y || pt.x === this.rightSE.point.x && pt.y === this.rightSE.point.y;
  1102. }
  1103. /* Compare this segment with a point.
  1104. *
  1105. * A point P is considered to be colinear to a segment if there
  1106. * exists a distance D such that if we travel along the segment
  1107. * from one * endpoint towards the other a distance D, we find
  1108. * ourselves at point P.
  1109. *
  1110. * Return value indicates:
  1111. *
  1112. * 1: point lies above the segment (to the left of vertical)
  1113. * 0: point is colinear to segment
  1114. * -1: point lies below the segment (to the right of vertical)
  1115. */
  1116. }, {
  1117. key: "comparePoint",
  1118. value: function comparePoint(point) {
  1119. if (this.isAnEndpoint(point)) return 0;
  1120. var lPt = this.leftSE.point;
  1121. var rPt = this.rightSE.point;
  1122. var v = this.vector(); // Exactly vertical segments.
  1123. if (lPt.x === rPt.x) {
  1124. if (point.x === lPt.x) return 0;
  1125. return point.x < lPt.x ? 1 : -1;
  1126. } // Nearly vertical segments with an intersection.
  1127. // Check to see where a point on the line with matching Y coordinate is.
  1128. var yDist = (point.y - lPt.y) / v.y;
  1129. var xFromYDist = lPt.x + yDist * v.x;
  1130. if (point.x === xFromYDist) return 0; // General case.
  1131. // Check to see where a point on the line with matching X coordinate is.
  1132. var xDist = (point.x - lPt.x) / v.x;
  1133. var yFromXDist = lPt.y + xDist * v.y;
  1134. if (point.y === yFromXDist) return 0;
  1135. return point.y < yFromXDist ? -1 : 1;
  1136. }
  1137. /**
  1138. * Given another segment, returns the first non-trivial intersection
  1139. * between the two segments (in terms of sweep line ordering), if it exists.
  1140. *
  1141. * A 'non-trivial' intersection is one that will cause one or both of the
  1142. * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
  1143. *
  1144. * * endpoint of segA with endpoint of segB --> trivial
  1145. * * endpoint of segA with point along segB --> non-trivial
  1146. * * endpoint of segB with point along segA --> non-trivial
  1147. * * point along segA with point along segB --> non-trivial
  1148. *
  1149. * If no non-trivial intersection exists, return null
  1150. * Else, return null.
  1151. */
  1152. }, {
  1153. key: "getIntersection",
  1154. value: function getIntersection(other) {
  1155. // If bboxes don't overlap, there can't be any intersections
  1156. var tBbox = this.bbox();
  1157. var oBbox = other.bbox();
  1158. var bboxOverlap = getBboxOverlap(tBbox, oBbox);
  1159. if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
  1160. // This will 'snap' intersections to endpoints if possible, and will
  1161. // handle cases of colinearity.
  1162. var tlp = this.leftSE.point;
  1163. var trp = this.rightSE.point;
  1164. var olp = other.leftSE.point;
  1165. var orp = other.rightSE.point; // does each endpoint touch the other segment?
  1166. // note that we restrict the 'touching' definition to only allow segments
  1167. // to touch endpoints that lie forward from where we are in the sweep line pass
  1168. var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
  1169. var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
  1170. var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
  1171. var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
  1172. if (touchesThisLSE && touchesOtherLSE) {
  1173. // these two cases are for colinear segments with matching left
  1174. // endpoints, and one segment being longer than the other
  1175. if (touchesThisRSE && !touchesOtherRSE) return trp;
  1176. if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
  1177. // or just on their left endpoint (one trivial intersection
  1178. return null;
  1179. } // does this left endpoint matches (other doesn't)
  1180. if (touchesThisLSE) {
  1181. // check for segments that just intersect on opposing endpoints
  1182. if (touchesOtherRSE) {
  1183. if (tlp.x === orp.x && tlp.y === orp.y) return null;
  1184. } // t-intersection on left endpoint
  1185. return tlp;
  1186. } // does other left endpoint matches (this doesn't)
  1187. if (touchesOtherLSE) {
  1188. // check for segments that just intersect on opposing endpoints
  1189. if (touchesThisRSE) {
  1190. if (trp.x === olp.x && trp.y === olp.y) return null;
  1191. } // t-intersection on left endpoint
  1192. return olp;
  1193. } // trivial intersection on right endpoints
  1194. if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
  1195. if (touchesThisRSE) return trp;
  1196. if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
  1197. // infinite lines laid over the segments
  1198. var pt = intersection(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
  1199. // they would have an endpoint intersection and that case was already handled above
  1200. if (pt === null) return null; // is the intersection found between the lines not on the segments?
  1201. if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
  1202. return rounder.round(pt.x, pt.y);
  1203. }
  1204. /**
  1205. * Split the given segment into multiple segments on the given points.
  1206. * * Each existing segment will retain its leftSE and a new rightSE will be
  1207. * generated for it.
  1208. * * A new segment will be generated which will adopt the original segment's
  1209. * rightSE, and a new leftSE will be generated for it.
  1210. * * If there are more than two points given to split on, new segments
  1211. * in the middle will be generated with new leftSE and rightSE's.
  1212. * * An array of the newly generated SweepEvents will be returned.
  1213. *
  1214. * Warning: input array of points is modified
  1215. */
  1216. }, {
  1217. key: "split",
  1218. value: function split(point) {
  1219. var newEvents = [];
  1220. var alreadyLinked = point.events !== undefined;
  1221. var newLeftSE = new SweepEvent(point, true);
  1222. var newRightSE = new SweepEvent(point, false);
  1223. var oldRightSE = this.rightSE;
  1224. this.replaceRightSE(newRightSE);
  1225. newEvents.push(newRightSE);
  1226. newEvents.push(newLeftSE);
  1227. var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
  1228. // sometimes one of the resulting new segments is vertical, in which
  1229. // case its left and right events may need to be swapped
  1230. if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
  1231. newSeg.swapEvents();
  1232. }
  1233. if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
  1234. this.swapEvents();
  1235. } // in the point we just used to create new sweep events with was already
  1236. // linked to other events, we need to check if either of the affected
  1237. // segments should be consumed
  1238. if (alreadyLinked) {
  1239. newLeftSE.checkForConsuming();
  1240. newRightSE.checkForConsuming();
  1241. }
  1242. return newEvents;
  1243. }
  1244. /* Swap which event is left and right */
  1245. }, {
  1246. key: "swapEvents",
  1247. value: function swapEvents() {
  1248. var tmpEvt = this.rightSE;
  1249. this.rightSE = this.leftSE;
  1250. this.leftSE = tmpEvt;
  1251. this.leftSE.isLeft = true;
  1252. this.rightSE.isLeft = false;
  1253. for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
  1254. this.windings[i] *= -1;
  1255. }
  1256. }
  1257. /* Consume another segment. We take their rings under our wing
  1258. * and mark them as consumed. Use for perfectly overlapping segments */
  1259. }, {
  1260. key: "consume",
  1261. value: function consume(other) {
  1262. var consumer = this;
  1263. var consumee = other;
  1264. while (consumer.consumedBy) {
  1265. consumer = consumer.consumedBy;
  1266. }
  1267. while (consumee.consumedBy) {
  1268. consumee = consumee.consumedBy;
  1269. }
  1270. var cmp = Segment.compare(consumer, consumee);
  1271. if (cmp === 0) return; // already consumed
  1272. // the winner of the consumption is the earlier segment
  1273. // according to sweep line ordering
  1274. if (cmp > 0) {
  1275. var tmp = consumer;
  1276. consumer = consumee;
  1277. consumee = tmp;
  1278. } // make sure a segment doesn't consume it's prev
  1279. if (consumer.prev === consumee) {
  1280. var _tmp = consumer;
  1281. consumer = consumee;
  1282. consumee = _tmp;
  1283. }
  1284. for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
  1285. var ring = consumee.rings[i];
  1286. var winding = consumee.windings[i];
  1287. var index = consumer.rings.indexOf(ring);
  1288. if (index === -1) {
  1289. consumer.rings.push(ring);
  1290. consumer.windings.push(winding);
  1291. } else consumer.windings[index] += winding;
  1292. }
  1293. consumee.rings = null;
  1294. consumee.windings = null;
  1295. consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
  1296. consumee.leftSE.consumedBy = consumer.leftSE;
  1297. consumee.rightSE.consumedBy = consumer.rightSE;
  1298. }
  1299. /* The first segment previous segment chain that is in the result */
  1300. }, {
  1301. key: "prevInResult",
  1302. value: function prevInResult() {
  1303. if (this._prevInResult !== undefined) return this._prevInResult;
  1304. if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
  1305. return this._prevInResult;
  1306. }
  1307. }, {
  1308. key: "beforeState",
  1309. value: function beforeState() {
  1310. if (this._beforeState !== undefined) return this._beforeState;
  1311. if (!this.prev) this._beforeState = {
  1312. rings: [],
  1313. windings: [],
  1314. multiPolys: []
  1315. };else {
  1316. var seg = this.prev.consumedBy || this.prev;
  1317. this._beforeState = seg.afterState();
  1318. }
  1319. return this._beforeState;
  1320. }
  1321. }, {
  1322. key: "afterState",
  1323. value: function afterState() {
  1324. if (this._afterState !== undefined) return this._afterState;
  1325. var beforeState = this.beforeState();
  1326. this._afterState = {
  1327. rings: beforeState.rings.slice(0),
  1328. windings: beforeState.windings.slice(0),
  1329. multiPolys: []
  1330. };
  1331. var ringsAfter = this._afterState.rings;
  1332. var windingsAfter = this._afterState.windings;
  1333. var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
  1334. for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
  1335. var ring = this.rings[i];
  1336. var winding = this.windings[i];
  1337. var index = ringsAfter.indexOf(ring);
  1338. if (index === -1) {
  1339. ringsAfter.push(ring);
  1340. windingsAfter.push(winding);
  1341. } else windingsAfter[index] += winding;
  1342. } // calcualte polysAfter
  1343. var polysAfter = [];
  1344. var polysExclude = [];
  1345. for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
  1346. if (windingsAfter[_i] === 0) continue; // non-zero rule
  1347. var _ring = ringsAfter[_i];
  1348. var poly = _ring.poly;
  1349. if (polysExclude.indexOf(poly) !== -1) continue;
  1350. if (_ring.isExterior) polysAfter.push(poly);else {
  1351. if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
  1352. var _index = polysAfter.indexOf(_ring.poly);
  1353. if (_index !== -1) polysAfter.splice(_index, 1);
  1354. }
  1355. } // calculate multiPolysAfter
  1356. for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
  1357. var mp = polysAfter[_i2].multiPoly;
  1358. if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
  1359. }
  1360. return this._afterState;
  1361. }
  1362. /* Is this segment part of the final result? */
  1363. }, {
  1364. key: "isInResult",
  1365. value: function isInResult() {
  1366. // if we've been consumed, we're not in the result
  1367. if (this.consumedBy) return false;
  1368. if (this._isInResult !== undefined) return this._isInResult;
  1369. var mpsBefore = this.beforeState().multiPolys;
  1370. var mpsAfter = this.afterState().multiPolys;
  1371. switch (operation.type) {
  1372. case 'union':
  1373. {
  1374. // UNION - included iff:
  1375. // * On one side of us there is 0 poly interiors AND
  1376. // * On the other side there is 1 or more.
  1377. var noBefores = mpsBefore.length === 0;
  1378. var noAfters = mpsAfter.length === 0;
  1379. this._isInResult = noBefores !== noAfters;
  1380. break;
  1381. }
  1382. case 'intersection':
  1383. {
  1384. // INTERSECTION - included iff:
  1385. // * on one side of us all multipolys are rep. with poly interiors AND
  1386. // * on the other side of us, not all multipolys are repsented
  1387. // with poly interiors
  1388. var least;
  1389. var most;
  1390. if (mpsBefore.length < mpsAfter.length) {
  1391. least = mpsBefore.length;
  1392. most = mpsAfter.length;
  1393. } else {
  1394. least = mpsAfter.length;
  1395. most = mpsBefore.length;
  1396. }
  1397. this._isInResult = most === operation.numMultiPolys && least < most;
  1398. break;
  1399. }
  1400. case 'xor':
  1401. {
  1402. // XOR - included iff:
  1403. // * the difference between the number of multipolys represented
  1404. // with poly interiors on our two sides is an odd number
  1405. var diff = Math.abs(mpsBefore.length - mpsAfter.length);
  1406. this._isInResult = diff % 2 === 1;
  1407. break;
  1408. }
  1409. case 'difference':
  1410. {
  1411. // DIFFERENCE included iff:
  1412. // * on exactly one side, we have just the subject
  1413. var isJustSubject = function isJustSubject(mps) {
  1414. return mps.length === 1 && mps[0].isSubject;
  1415. };
  1416. this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
  1417. break;
  1418. }
  1419. default:
  1420. throw new Error("Unrecognized operation type found ".concat(operation.type));
  1421. }
  1422. return this._isInResult;
  1423. }
  1424. }], [{
  1425. key: "fromRing",
  1426. value: function fromRing(pt1, pt2, ring) {
  1427. var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
  1428. var cmpPts = SweepEvent.comparePoints(pt1, pt2);
  1429. if (cmpPts < 0) {
  1430. leftPt = pt1;
  1431. rightPt = pt2;
  1432. winding = 1;
  1433. } else if (cmpPts > 0) {
  1434. leftPt = pt2;
  1435. rightPt = pt1;
  1436. winding = -1;
  1437. } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
  1438. var leftSE = new SweepEvent(leftPt, true);
  1439. var rightSE = new SweepEvent(rightPt, false);
  1440. return new Segment(leftSE, rightSE, [ring], [winding]);
  1441. }
  1442. }]);
  1443. return Segment;
  1444. }();
  1445. var RingIn = /*#__PURE__*/function () {
  1446. function RingIn(geomRing, poly, isExterior) {
  1447. _classCallCheck(this, RingIn);
  1448. if (!Array.isArray(geomRing) || geomRing.length === 0) {
  1449. throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
  1450. }
  1451. this.poly = poly;
  1452. this.isExterior = isExterior;
  1453. this.segments = [];
  1454. if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
  1455. throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
  1456. }
  1457. var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
  1458. this.bbox = {
  1459. ll: {
  1460. x: firstPoint.x,
  1461. y: firstPoint.y
  1462. },
  1463. ur: {
  1464. x: firstPoint.x,
  1465. y: firstPoint.y
  1466. }
  1467. };
  1468. var prevPoint = firstPoint;
  1469. for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
  1470. if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
  1471. throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
  1472. }
  1473. var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
  1474. if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
  1475. this.segments.push(Segment.fromRing(prevPoint, point, this));
  1476. if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
  1477. if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
  1478. if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
  1479. if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
  1480. prevPoint = point;
  1481. } // add segment from last to first if last is not the same as first
  1482. if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
  1483. this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
  1484. }
  1485. }
  1486. _createClass(RingIn, [{
  1487. key: "getSweepEvents",
  1488. value: function getSweepEvents() {
  1489. var sweepEvents = [];
  1490. for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
  1491. var segment = this.segments[i];
  1492. sweepEvents.push(segment.leftSE);
  1493. sweepEvents.push(segment.rightSE);
  1494. }
  1495. return sweepEvents;
  1496. }
  1497. }]);
  1498. return RingIn;
  1499. }();
  1500. var PolyIn = /*#__PURE__*/function () {
  1501. function PolyIn(geomPoly, multiPoly) {
  1502. _classCallCheck(this, PolyIn);
  1503. if (!Array.isArray(geomPoly)) {
  1504. throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
  1505. }
  1506. this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
  1507. this.bbox = {
  1508. ll: {
  1509. x: this.exteriorRing.bbox.ll.x,
  1510. y: this.exteriorRing.bbox.ll.y
  1511. },
  1512. ur: {
  1513. x: this.exteriorRing.bbox.ur.x,
  1514. y: this.exteriorRing.bbox.ur.y
  1515. }
  1516. };
  1517. this.interiorRings = [];
  1518. for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
  1519. var ring = new RingIn(geomPoly[i], this, false);
  1520. if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
  1521. if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
  1522. if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
  1523. if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
  1524. this.interiorRings.push(ring);
  1525. }
  1526. this.multiPoly = multiPoly;
  1527. }
  1528. _createClass(PolyIn, [{
  1529. key: "getSweepEvents",
  1530. value: function getSweepEvents() {
  1531. var sweepEvents = this.exteriorRing.getSweepEvents();
  1532. for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
  1533. var ringSweepEvents = this.interiorRings[i].getSweepEvents();
  1534. for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
  1535. sweepEvents.push(ringSweepEvents[j]);
  1536. }
  1537. }
  1538. return sweepEvents;
  1539. }
  1540. }]);
  1541. return PolyIn;
  1542. }();
  1543. var MultiPolyIn = /*#__PURE__*/function () {
  1544. function MultiPolyIn(geom, isSubject) {
  1545. _classCallCheck(this, MultiPolyIn);
  1546. if (!Array.isArray(geom)) {
  1547. throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
  1548. }
  1549. try {
  1550. // if the input looks like a polygon, convert it to a multipolygon
  1551. if (typeof geom[0][0][0] === 'number') geom = [geom];
  1552. } catch (ex) {// The input is either malformed or has empty arrays.
  1553. // In either case, it will be handled later on.
  1554. }
  1555. this.polys = [];
  1556. this.bbox = {
  1557. ll: {
  1558. x: Number.POSITIVE_INFINITY,
  1559. y: Number.POSITIVE_INFINITY
  1560. },
  1561. ur: {
  1562. x: Number.NEGATIVE_INFINITY,
  1563. y: Number.NEGATIVE_INFINITY
  1564. }
  1565. };
  1566. for (var i = 0, iMax = geom.length; i < iMax; i++) {
  1567. var poly = new PolyIn(geom[i], this);
  1568. if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
  1569. if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
  1570. if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
  1571. if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
  1572. this.polys.push(poly);
  1573. }
  1574. this.isSubject = isSubject;
  1575. }
  1576. _createClass(MultiPolyIn, [{
  1577. key: "getSweepEvents",
  1578. value: function getSweepEvents() {
  1579. var sweepEvents = [];
  1580. for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
  1581. var polySweepEvents = this.polys[i].getSweepEvents();
  1582. for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
  1583. sweepEvents.push(polySweepEvents[j]);
  1584. }
  1585. }
  1586. return sweepEvents;
  1587. }
  1588. }]);
  1589. return MultiPolyIn;
  1590. }();
  1591. var RingOut = /*#__PURE__*/function () {
  1592. _createClass(RingOut, null, [{
  1593. key: "factory",
  1594. /* Given the segments from the sweep line pass, compute & return a series
  1595. * of closed rings from all the segments marked to be part of the result */
  1596. value: function factory(allSegments) {
  1597. var ringsOut = [];
  1598. for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
  1599. var segment = allSegments[i];
  1600. if (!segment.isInResult() || segment.ringOut) continue;
  1601. var prevEvent = null;
  1602. var event = segment.leftSE;
  1603. var nextEvent = segment.rightSE;
  1604. var events = [event];
  1605. var startingPoint = event.point;
  1606. var intersectionLEs = [];
  1607. /* Walk the chain of linked events to form a closed ring */
  1608. while (true) {
  1609. prevEvent = event;
  1610. event = nextEvent;
  1611. events.push(event);
  1612. /* Is the ring complete? */
  1613. if (event.point === startingPoint) break;
  1614. while (true) {
  1615. var availableLEs = event.getAvailableLinkedEvents();
  1616. /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
  1617. * part of the algorithm malfunctioned... please file a bug report. */
  1618. if (availableLEs.length === 0) {
  1619. var firstPt = events[0].point;
  1620. var lastPt = events[events.length - 1].point;
  1621. throw new Error("Unable to complete output ring starting at [".concat(firstPt.x, ",") + " ".concat(firstPt.y, "]. Last matching segment found ends at") + " [".concat(lastPt.x, ", ").concat(lastPt.y, "]."));
  1622. }
  1623. /* Only one way to go, so cotinue on the path */
  1624. if (availableLEs.length === 1) {
  1625. nextEvent = availableLEs[0].otherSE;
  1626. break;
  1627. }
  1628. /* We must have an intersection. Check for a completed loop */
  1629. var indexLE = null;
  1630. for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
  1631. if (intersectionLEs[j].point === event.point) {
  1632. indexLE = j;
  1633. break;
  1634. }
  1635. }
  1636. /* Found a completed loop. Cut that off and make a ring */
  1637. if (indexLE !== null) {
  1638. var intersectionLE = intersectionLEs.splice(indexLE)[0];
  1639. var ringEvents = events.splice(intersectionLE.index);
  1640. ringEvents.unshift(ringEvents[0].otherSE);
  1641. ringsOut.push(new RingOut(ringEvents.reverse()));
  1642. continue;
  1643. }
  1644. /* register the intersection */
  1645. intersectionLEs.push({
  1646. index: events.length,
  1647. point: event.point
  1648. });
  1649. /* Choose the left-most option to continue the walk */
  1650. var comparator = event.getLeftmostComparator(prevEvent);
  1651. nextEvent = availableLEs.sort(comparator)[0].otherSE;
  1652. break;
  1653. }
  1654. }
  1655. ringsOut.push(new RingOut(events));
  1656. }
  1657. return ringsOut;
  1658. }
  1659. }]);
  1660. function RingOut(events) {
  1661. _classCallCheck(this, RingOut);
  1662. this.events = events;
  1663. for (var i = 0, iMax = events.length; i < iMax; i++) {
  1664. events[i].segment.ringOut = this;
  1665. }
  1666. this.poly = null;
  1667. }
  1668. _createClass(RingOut, [{
  1669. key: "getGeom",
  1670. value: function getGeom() {
  1671. // Remove superfluous points (ie extra points along a straight line),
  1672. var prevPt = this.events[0].point;
  1673. var points = [prevPt];
  1674. for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
  1675. var _pt = this.events[i].point;
  1676. var _nextPt = this.events[i + 1].point;
  1677. if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
  1678. points.push(_pt);
  1679. prevPt = _pt;
  1680. } // ring was all (within rounding error of angle calc) colinear points
  1681. if (points.length === 1) return null; // check if the starting point is necessary
  1682. var pt = points[0];
  1683. var nextPt = points[1];
  1684. if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
  1685. points.push(points[0]);
  1686. var step = this.isExteriorRing() ? 1 : -1;
  1687. var iStart = this.isExteriorRing() ? 0 : points.length - 1;
  1688. var iEnd = this.isExteriorRing() ? points.length : -1;
  1689. var orderedPoints = [];
  1690. for (var _i = iStart; _i != iEnd; _i += step) {
  1691. orderedPoints.push([points[_i].x, points[_i].y]);
  1692. }
  1693. return orderedPoints;
  1694. }
  1695. }, {
  1696. key: "isExteriorRing",
  1697. value: function isExteriorRing() {
  1698. if (this._isExteriorRing === undefined) {
  1699. var enclosing = this.enclosingRing();
  1700. this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
  1701. }
  1702. return this._isExteriorRing;
  1703. }
  1704. }, {
  1705. key: "enclosingRing",
  1706. value: function enclosingRing() {
  1707. if (this._enclosingRing === undefined) {
  1708. this._enclosingRing = this._calcEnclosingRing();
  1709. }
  1710. return this._enclosingRing;
  1711. }
  1712. /* Returns the ring that encloses this one, if any */
  1713. }, {
  1714. key: "_calcEnclosingRing",
  1715. value: function _calcEnclosingRing() {
  1716. // start with the ealier sweep line event so that the prevSeg
  1717. // chain doesn't lead us inside of a loop of ours
  1718. var leftMostEvt = this.events[0];
  1719. for (var i = 1, iMax = this.events.length; i < iMax; i++) {
  1720. var evt = this.events[i];
  1721. if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
  1722. }
  1723. var prevSeg = leftMostEvt.segment.prevInResult();
  1724. var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
  1725. while (true) {
  1726. // no segment found, thus no ring can enclose us
  1727. if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
  1728. // segment must loop back around and enclose us
  1729. if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
  1730. // segment must either loop around us or the ring of the prev prev
  1731. // seg, which would make us and the ring of the prev peers
  1732. if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
  1733. if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
  1734. return prevSeg.ringOut;
  1735. } else return prevSeg.ringOut.enclosingRing();
  1736. } // two segments are from the same ring, so this was a penisula
  1737. // of that ring. iterate downward, keep searching
  1738. prevSeg = prevPrevSeg.prevInResult();
  1739. prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
  1740. }
  1741. }
  1742. }]);
  1743. return RingOut;
  1744. }();
  1745. var PolyOut = /*#__PURE__*/function () {
  1746. function PolyOut(exteriorRing) {
  1747. _classCallCheck(this, PolyOut);
  1748. this.exteriorRing = exteriorRing;
  1749. exteriorRing.poly = this;
  1750. this.interiorRings = [];
  1751. }
  1752. _createClass(PolyOut, [{
  1753. key: "addInterior",
  1754. value: function addInterior(ring) {
  1755. this.interiorRings.push(ring);
  1756. ring.poly = this;
  1757. }
  1758. }, {
  1759. key: "getGeom",
  1760. value: function getGeom() {
  1761. var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
  1762. if (geom[0] === null) return null;
  1763. for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
  1764. var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
  1765. if (ringGeom === null) continue;
  1766. geom.push(ringGeom);
  1767. }
  1768. return geom;
  1769. }
  1770. }]);
  1771. return PolyOut;
  1772. }();
  1773. var MultiPolyOut = /*#__PURE__*/function () {
  1774. function MultiPolyOut(rings) {
  1775. _classCallCheck(this, MultiPolyOut);
  1776. this.rings = rings;
  1777. this.polys = this._composePolys(rings);
  1778. }
  1779. _createClass(MultiPolyOut, [{
  1780. key: "getGeom",
  1781. value: function getGeom() {
  1782. var geom = [];
  1783. for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
  1784. var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
  1785. if (polyGeom === null) continue;
  1786. geom.push(polyGeom);
  1787. }
  1788. return geom;
  1789. }
  1790. }, {
  1791. key: "_composePolys",
  1792. value: function _composePolys(rings) {
  1793. var polys = [];
  1794. for (var i = 0, iMax = rings.length; i < iMax; i++) {
  1795. var ring = rings[i];
  1796. if (ring.poly) continue;
  1797. if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
  1798. var enclosingRing = ring.enclosingRing();
  1799. if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
  1800. enclosingRing.poly.addInterior(ring);
  1801. }
  1802. }
  1803. return polys;
  1804. }
  1805. }]);
  1806. return MultiPolyOut;
  1807. }();
  1808. /**
  1809. * NOTE: We must be careful not to change any segments while
  1810. * they are in the SplayTree. AFAIK, there's no way to tell
  1811. * the tree to rebalance itself - thus before splitting
  1812. * a segment that's in the tree, we remove it from the tree,
  1813. * do the split, then re-insert it. (Even though splitting a
  1814. * segment *shouldn't* change its correct position in the
  1815. * sweep line tree, the reality is because of rounding errors,
  1816. * it sometimes does.)
  1817. */
  1818. var SweepLine = /*#__PURE__*/function () {
  1819. function SweepLine(queue) {
  1820. var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
  1821. _classCallCheck(this, SweepLine);
  1822. this.queue = queue;
  1823. this.tree = new Tree(comparator);
  1824. this.segments = [];
  1825. }
  1826. _createClass(SweepLine, [{
  1827. key: "process",
  1828. value: function process(event) {
  1829. var segment = event.segment;
  1830. var newEvents = []; // if we've already been consumed by another segment,
  1831. // clean up our body parts and get out
  1832. if (event.consumedBy) {
  1833. if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
  1834. return newEvents;
  1835. }
  1836. var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
  1837. if (!node) throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + 'in SweepLine tree. Please submit a bug report.');
  1838. var prevNode = node;
  1839. var nextNode = node;
  1840. var prevSeg = undefined;
  1841. var nextSeg = undefined; // skip consumed segments still in tree
  1842. while (prevSeg === undefined) {
  1843. prevNode = this.tree.prev(prevNode);
  1844. if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
  1845. } // skip consumed segments still in tree
  1846. while (nextSeg === undefined) {
  1847. nextNode = this.tree.next(nextNode);
  1848. if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
  1849. }
  1850. if (event.isLeft) {
  1851. // Check for intersections against the previous segment in the sweep line
  1852. var prevMySplitter = null;
  1853. if (prevSeg) {
  1854. var prevInter = prevSeg.getIntersection(segment);
  1855. if (prevInter !== null) {
  1856. if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
  1857. if (!prevSeg.isAnEndpoint(prevInter)) {
  1858. var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
  1859. for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  1860. newEvents.push(newEventsFromSplit[i]);
  1861. }
  1862. }
  1863. }
  1864. } // Check for intersections against the next segment in the sweep line
  1865. var nextMySplitter = null;
  1866. if (nextSeg) {
  1867. var nextInter = nextSeg.getIntersection(segment);
  1868. if (nextInter !== null) {
  1869. if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
  1870. if (!nextSeg.isAnEndpoint(nextInter)) {
  1871. var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
  1872. for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
  1873. newEvents.push(_newEventsFromSplit[_i]);
  1874. }
  1875. }
  1876. }
  1877. } // For simplicity, even if we find more than one intersection we only
  1878. // spilt on the 'earliest' (sweep-line style) of the intersections.
  1879. // The other intersection will be handled in a future process().
  1880. if (prevMySplitter !== null || nextMySplitter !== null) {
  1881. var mySplitter = null;
  1882. if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
  1883. var cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
  1884. mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
  1885. } // Rounding errors can cause changes in ordering,
  1886. // so remove afected segments and right sweep events before splitting
  1887. this.queue.remove(segment.rightSE);
  1888. newEvents.push(segment.rightSE);
  1889. var _newEventsFromSplit2 = segment.split(mySplitter);
  1890. for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
  1891. newEvents.push(_newEventsFromSplit2[_i2]);
  1892. }
  1893. }
  1894. if (newEvents.length > 0) {
  1895. // We found some intersections, so re-do the current event to
  1896. // make sure sweep line ordering is totally consistent for later
  1897. // use with the segment 'prev' pointers
  1898. this.tree.remove(segment);
  1899. newEvents.push(event);
  1900. } else {
  1901. // done with left event
  1902. this.segments.push(segment);
  1903. segment.prev = prevSeg;
  1904. }
  1905. } else {
  1906. // event.isRight
  1907. // since we're about to be removed from the sweep line, check for
  1908. // intersections between our previous and next segments
  1909. if (prevSeg && nextSeg) {
  1910. var inter = prevSeg.getIntersection(nextSeg);
  1911. if (inter !== null) {
  1912. if (!prevSeg.isAnEndpoint(inter)) {
  1913. var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
  1914. for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
  1915. newEvents.push(_newEventsFromSplit3[_i3]);
  1916. }
  1917. }
  1918. if (!nextSeg.isAnEndpoint(inter)) {
  1919. var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
  1920. for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
  1921. newEvents.push(_newEventsFromSplit4[_i4]);
  1922. }
  1923. }
  1924. }
  1925. }
  1926. this.tree.remove(segment);
  1927. }
  1928. return newEvents;
  1929. }
  1930. /* Safely split a segment that is currently in the datastructures
  1931. * IE - a segment other than the one that is currently being processed. */
  1932. }, {
  1933. key: "_splitSafely",
  1934. value: function _splitSafely(seg, pt) {
  1935. // Rounding errors can cause changes in ordering,
  1936. // so remove afected segments and right sweep events before splitting
  1937. // removeNode() doesn't work, so have re-find the seg
  1938. // https://github.com/w8r/splay-tree/pull/5
  1939. this.tree.remove(seg);
  1940. var rightSE = seg.rightSE;
  1941. this.queue.remove(rightSE);
  1942. var newEvents = seg.split(pt);
  1943. newEvents.push(rightSE); // splitting can trigger consumption
  1944. if (seg.consumedBy === undefined) this.tree.insert(seg);
  1945. return newEvents;
  1946. }
  1947. }]);
  1948. return SweepLine;
  1949. }();
  1950. var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
  1951. var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
  1952. var Operation = /*#__PURE__*/function () {
  1953. function Operation() {
  1954. _classCallCheck(this, Operation);
  1955. }
  1956. _createClass(Operation, [{
  1957. key: "run",
  1958. value: function run(type, geom, moreGeoms) {
  1959. operation.type = type;
  1960. rounder.reset();
  1961. /* Convert inputs to MultiPoly objects */
  1962. var multipolys = [new MultiPolyIn(geom, true)];
  1963. for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
  1964. multipolys.push(new MultiPolyIn(moreGeoms[i], false));
  1965. }
  1966. operation.numMultiPolys = multipolys.length;
  1967. /* BBox optimization for difference operation
  1968. * If the bbox of a multipolygon that's part of the clipping doesn't
  1969. * intersect the bbox of the subject at all, we can just drop that
  1970. * multiploygon. */
  1971. if (operation.type === 'difference') {
  1972. // in place removal
  1973. var subject = multipolys[0];
  1974. var _i = 1;
  1975. while (_i < multipolys.length) {
  1976. if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
  1977. }
  1978. }
  1979. /* BBox optimization for intersection operation
  1980. * If we can find any pair of multipolygons whose bbox does not overlap,
  1981. * then the result will be empty. */
  1982. if (operation.type === 'intersection') {
  1983. // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
  1984. // it could be optimized to O(n * ln(n))
  1985. for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
  1986. var mpA = multipolys[_i2];
  1987. for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
  1988. if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
  1989. }
  1990. }
  1991. }
  1992. /* Put segment endpoints in a priority queue */
  1993. var queue = new Tree(SweepEvent.compare);
  1994. for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
  1995. var sweepEvents = multipolys[_i3].getSweepEvents();
  1996. for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
  1997. queue.insert(sweepEvents[_j]);
  1998. if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
  1999. // prevents an infinite loop, an otherwise common manifestation of bugs
  2000. throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
  2001. }
  2002. }
  2003. }
  2004. /* Pass the sweep line over those endpoints */
  2005. var sweepLine = new SweepLine(queue);
  2006. var prevQueueSize = queue.size;
  2007. var node = queue.pop();
  2008. while (node) {
  2009. var evt = node.key;
  2010. if (queue.size === prevQueueSize) {
  2011. // prevents an infinite loop, an otherwise common manifestation of bugs
  2012. var seg = evt.segment;
  2013. throw new Error("Unable to pop() ".concat(evt.isLeft ? 'left' : 'right', " SweepEvent ") + "[".concat(evt.point.x, ", ").concat(evt.point.y, "] from segment #").concat(seg.id, " ") + "[".concat(seg.leftSE.point.x, ", ").concat(seg.leftSE.point.y, "] -> ") + "[".concat(seg.rightSE.point.x, ", ").concat(seg.rightSE.point.y, "] from queue. ") + 'Please file a bug report.');
  2014. }
  2015. if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
  2016. // prevents an infinite loop, an otherwise common manifestation of bugs
  2017. throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
  2018. }
  2019. if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
  2020. // prevents an infinite loop, an otherwise common manifestation of bugs
  2021. throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
  2022. }
  2023. var newEvents = sweepLine.process(evt);
  2024. for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
  2025. var _evt = newEvents[_i4];
  2026. if (_evt.consumedBy === undefined) queue.insert(_evt);
  2027. }
  2028. prevQueueSize = queue.size;
  2029. node = queue.pop();
  2030. } // free some memory we don't need anymore
  2031. rounder.reset();
  2032. /* Collect and compile segments we're keeping into a multipolygon */
  2033. var ringsOut = RingOut.factory(sweepLine.segments);
  2034. var result = new MultiPolyOut(ringsOut);
  2035. return result.getGeom();
  2036. }
  2037. }]);
  2038. return Operation;
  2039. }(); // singleton available by import
  2040. var operation = new Operation();
  2041. var union = function union(geom) {
  2042. for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  2043. moreGeoms[_key - 1] = arguments[_key];
  2044. }
  2045. return operation.run('union', geom, moreGeoms);
  2046. };
  2047. var intersection$1 = function intersection(geom) {
  2048. for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  2049. moreGeoms[_key2 - 1] = arguments[_key2];
  2050. }
  2051. return operation.run('intersection', geom, moreGeoms);
  2052. };
  2053. var xor = function xor(geom) {
  2054. for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
  2055. moreGeoms[_key3 - 1] = arguments[_key3];
  2056. }
  2057. return operation.run('xor', geom, moreGeoms);
  2058. };
  2059. var difference = function difference(subjectGeom) {
  2060. for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
  2061. clippingGeoms[_key4 - 1] = arguments[_key4];
  2062. }
  2063. return operation.run('difference', subjectGeom, clippingGeoms);
  2064. };
  2065. var index = {
  2066. union: union,
  2067. intersection: intersection$1,
  2068. xor: xor,
  2069. difference: difference
  2070. };
  2071. return index;
  2072. })));