index.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. // src/geom-in.ts
  2. import BigNumber2 from "bignumber.js";
  3. // src/constant.ts
  4. var constant_default = (x) => {
  5. return () => {
  6. return x;
  7. };
  8. };
  9. // src/compare.ts
  10. var compare_default = (eps) => {
  11. const almostEqual = eps ? (a, b) => b.minus(a).abs().isLessThanOrEqualTo(eps) : constant_default(false);
  12. return (a, b) => {
  13. if (almostEqual(a, b)) return 0;
  14. return a.comparedTo(b);
  15. };
  16. };
  17. // src/orient.ts
  18. function orient_default(eps) {
  19. const almostCollinear = eps ? (area2, ax, ay, cx, cy) => area2.exponentiatedBy(2).isLessThanOrEqualTo(
  20. cx.minus(ax).exponentiatedBy(2).plus(cy.minus(ay).exponentiatedBy(2)).times(eps)
  21. ) : constant_default(false);
  22. return (a, b, c) => {
  23. const ax = a.x, ay = a.y, cx = c.x, cy = c.y;
  24. const area2 = ay.minus(cy).times(b.x.minus(cx)).minus(ax.minus(cx).times(b.y.minus(cy)));
  25. if (almostCollinear(area2, ax, ay, cx, cy)) return 0;
  26. return area2.comparedTo(0);
  27. };
  28. }
  29. // src/snap.ts
  30. import BigNumber from "bignumber.js";
  31. import { SplayTreeSet } from "splaytree-ts";
  32. // src/identity.ts
  33. var identity_default = (x) => {
  34. return x;
  35. };
  36. // src/snap.ts
  37. var snap_default = (eps) => {
  38. if (eps) {
  39. const xTree = new SplayTreeSet(compare_default(eps));
  40. const yTree = new SplayTreeSet(compare_default(eps));
  41. const snapCoord = (coord, tree) => {
  42. return tree.addAndReturn(coord);
  43. };
  44. const snap = (v) => {
  45. return {
  46. x: snapCoord(v.x, xTree),
  47. y: snapCoord(v.y, yTree)
  48. };
  49. };
  50. snap({ x: new BigNumber(0), y: new BigNumber(0) });
  51. return snap;
  52. }
  53. return identity_default;
  54. };
  55. // src/precision.ts
  56. var set = (eps) => {
  57. return {
  58. set: (eps2) => {
  59. precision = set(eps2);
  60. },
  61. reset: () => set(eps),
  62. compare: compare_default(eps),
  63. snap: snap_default(eps),
  64. orient: orient_default(eps)
  65. };
  66. };
  67. var precision = set();
  68. // src/bbox.ts
  69. var isInBbox = (bbox, point) => {
  70. return bbox.ll.x.isLessThanOrEqualTo(point.x) && point.x.isLessThanOrEqualTo(bbox.ur.x) && bbox.ll.y.isLessThanOrEqualTo(point.y) && point.y.isLessThanOrEqualTo(bbox.ur.y);
  71. };
  72. var getBboxOverlap = (b1, b2) => {
  73. if (b2.ur.x.isLessThan(b1.ll.x) || b1.ur.x.isLessThan(b2.ll.x) || b2.ur.y.isLessThan(b1.ll.y) || b1.ur.y.isLessThan(b2.ll.y))
  74. return null;
  75. const lowerX = b1.ll.x.isLessThan(b2.ll.x) ? b2.ll.x : b1.ll.x;
  76. const upperX = b1.ur.x.isLessThan(b2.ur.x) ? b1.ur.x : b2.ur.x;
  77. const lowerY = b1.ll.y.isLessThan(b2.ll.y) ? b2.ll.y : b1.ll.y;
  78. const upperY = b1.ur.y.isLessThan(b2.ur.y) ? b1.ur.y : b2.ur.y;
  79. return { ll: { x: lowerX, y: lowerY }, ur: { x: upperX, y: upperY } };
  80. };
  81. // src/operation.ts
  82. import { SplayTreeSet as SplayTreeSet3 } from "splaytree-ts";
  83. // src/vector.ts
  84. var crossProduct = (a, b) => a.x.times(b.y).minus(a.y.times(b.x));
  85. var dotProduct = (a, b) => a.x.times(b.x).plus(a.y.times(b.y));
  86. var length = (v) => dotProduct(v, v).sqrt();
  87. var sineOfAngle = (pShared, pBase, pAngle) => {
  88. const vBase = { x: pBase.x.minus(pShared.x), y: pBase.y.minus(pShared.y) };
  89. const vAngle = { x: pAngle.x.minus(pShared.x), y: pAngle.y.minus(pShared.y) };
  90. return crossProduct(vAngle, vBase).div(length(vAngle)).div(length(vBase));
  91. };
  92. var cosineOfAngle = (pShared, pBase, pAngle) => {
  93. const vBase = { x: pBase.x.minus(pShared.x), y: pBase.y.minus(pShared.y) };
  94. const vAngle = { x: pAngle.x.minus(pShared.x), y: pAngle.y.minus(pShared.y) };
  95. return dotProduct(vAngle, vBase).div(length(vAngle)).div(length(vBase));
  96. };
  97. var horizontalIntersection = (pt, v, y) => {
  98. if (v.y.isZero()) return null;
  99. return { x: pt.x.plus(v.x.div(v.y).times(y.minus(pt.y))), y };
  100. };
  101. var verticalIntersection = (pt, v, x) => {
  102. if (v.x.isZero()) return null;
  103. return { x, y: pt.y.plus(v.y.div(v.x).times(x.minus(pt.x))) };
  104. };
  105. var intersection = (pt1, v1, pt2, v2) => {
  106. if (v1.x.isZero()) return verticalIntersection(pt2, v2, pt1.x);
  107. if (v2.x.isZero()) return verticalIntersection(pt1, v1, pt2.x);
  108. if (v1.y.isZero()) return horizontalIntersection(pt2, v2, pt1.y);
  109. if (v2.y.isZero()) return horizontalIntersection(pt1, v1, pt2.y);
  110. const kross = crossProduct(v1, v2);
  111. if (kross.isZero()) return null;
  112. const ve = { x: pt2.x.minus(pt1.x), y: pt2.y.minus(pt1.y) };
  113. const d1 = crossProduct(ve, v1).div(kross);
  114. const d2 = crossProduct(ve, v2).div(kross);
  115. const x1 = pt1.x.plus(d2.times(v1.x)), x2 = pt2.x.plus(d1.times(v2.x));
  116. const y1 = pt1.y.plus(d2.times(v1.y)), y2 = pt2.y.plus(d1.times(v2.y));
  117. const x = x1.plus(x2).div(2);
  118. const y = y1.plus(y2).div(2);
  119. return { x, y };
  120. };
  121. // src/sweep-event.ts
  122. var SweepEvent = class _SweepEvent {
  123. point;
  124. isLeft;
  125. segment;
  126. otherSE;
  127. consumedBy;
  128. // for ordering sweep events in the sweep event queue
  129. static compare(a, b) {
  130. const ptCmp = _SweepEvent.comparePoints(a.point, b.point);
  131. if (ptCmp !== 0) return ptCmp;
  132. if (a.point !== b.point) a.link(b);
  133. if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1;
  134. return Segment.compare(a.segment, b.segment);
  135. }
  136. // for ordering points in sweep line order
  137. static comparePoints(aPt, bPt) {
  138. if (aPt.x.isLessThan(bPt.x)) return -1;
  139. if (aPt.x.isGreaterThan(bPt.x)) return 1;
  140. if (aPt.y.isLessThan(bPt.y)) return -1;
  141. if (aPt.y.isGreaterThan(bPt.y)) return 1;
  142. return 0;
  143. }
  144. // Warning: 'point' input will be modified and re-used (for performance)
  145. constructor(point, isLeft) {
  146. if (point.events === void 0) point.events = [this];
  147. else point.events.push(this);
  148. this.point = point;
  149. this.isLeft = isLeft;
  150. }
  151. link(other) {
  152. if (other.point === this.point) {
  153. throw new Error("Tried to link already linked events");
  154. }
  155. const otherEvents = other.point.events;
  156. for (let i = 0, iMax = otherEvents.length; i < iMax; i++) {
  157. const evt = otherEvents[i];
  158. this.point.events.push(evt);
  159. evt.point = this.point;
  160. }
  161. this.checkForConsuming();
  162. }
  163. /* Do a pass over our linked events and check to see if any pair
  164. * of segments match, and should be consumed. */
  165. checkForConsuming() {
  166. const numEvents = this.point.events.length;
  167. for (let i = 0; i < numEvents; i++) {
  168. const evt1 = this.point.events[i];
  169. if (evt1.segment.consumedBy !== void 0) continue;
  170. for (let j = i + 1; j < numEvents; j++) {
  171. const evt2 = this.point.events[j];
  172. if (evt2.consumedBy !== void 0) continue;
  173. if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
  174. evt1.segment.consume(evt2.segment);
  175. }
  176. }
  177. }
  178. getAvailableLinkedEvents() {
  179. const events = [];
  180. for (let i = 0, iMax = this.point.events.length; i < iMax; i++) {
  181. const evt = this.point.events[i];
  182. if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
  183. events.push(evt);
  184. }
  185. }
  186. return events;
  187. }
  188. /**
  189. * Returns a comparator function for sorting linked events that will
  190. * favor the event that will give us the smallest left-side angle.
  191. * All ring construction starts as low as possible heading to the right,
  192. * so by always turning left as sharp as possible we'll get polygons
  193. * without uncessary loops & holes.
  194. *
  195. * The comparator function has a compute cache such that it avoids
  196. * re-computing already-computed values.
  197. */
  198. getLeftmostComparator(baseEvent) {
  199. const cache = /* @__PURE__ */ new Map();
  200. const fillCache = (linkedEvent) => {
  201. const nextEvent = linkedEvent.otherSE;
  202. cache.set(linkedEvent, {
  203. sine: sineOfAngle(this.point, baseEvent.point, nextEvent.point),
  204. cosine: cosineOfAngle(this.point, baseEvent.point, nextEvent.point)
  205. });
  206. };
  207. return (a, b) => {
  208. if (!cache.has(a)) fillCache(a);
  209. if (!cache.has(b)) fillCache(b);
  210. const { sine: asine, cosine: acosine } = cache.get(a);
  211. const { sine: bsine, cosine: bcosine } = cache.get(b);
  212. if (asine.isGreaterThanOrEqualTo(0) && bsine.isGreaterThanOrEqualTo(0)) {
  213. if (acosine.isLessThan(bcosine)) return 1;
  214. if (acosine.isGreaterThan(bcosine)) return -1;
  215. return 0;
  216. }
  217. if (asine.isLessThan(0) && bsine.isLessThan(0)) {
  218. if (acosine.isLessThan(bcosine)) return -1;
  219. if (acosine.isGreaterThan(bcosine)) return 1;
  220. return 0;
  221. }
  222. if (bsine.isLessThan(asine)) return -1;
  223. if (bsine.isGreaterThan(asine)) return 1;
  224. return 0;
  225. };
  226. }
  227. };
  228. // src/geom-out.ts
  229. var RingOut = class _RingOut {
  230. events;
  231. poly;
  232. _isExteriorRing;
  233. _enclosingRing;
  234. /* Given the segments from the sweep line pass, compute & return a series
  235. * of closed rings from all the segments marked to be part of the result */
  236. static factory(allSegments) {
  237. const ringsOut = [];
  238. for (let i = 0, iMax = allSegments.length; i < iMax; i++) {
  239. const segment = allSegments[i];
  240. if (!segment.isInResult() || segment.ringOut) continue;
  241. let prevEvent = null;
  242. let event = segment.leftSE;
  243. let nextEvent = segment.rightSE;
  244. const events = [event];
  245. const startingPoint = event.point;
  246. const intersectionLEs = [];
  247. while (true) {
  248. prevEvent = event;
  249. event = nextEvent;
  250. events.push(event);
  251. if (event.point === startingPoint) break;
  252. while (true) {
  253. const availableLEs = event.getAvailableLinkedEvents();
  254. if (availableLEs.length === 0) {
  255. const firstPt = events[0].point;
  256. const lastPt = events[events.length - 1].point;
  257. throw new Error(
  258. `Unable to complete output ring starting at [${firstPt.x}, ${firstPt.y}]. Last matching segment found ends at [${lastPt.x}, ${lastPt.y}].`
  259. );
  260. }
  261. if (availableLEs.length === 1) {
  262. nextEvent = availableLEs[0].otherSE;
  263. break;
  264. }
  265. let indexLE = null;
  266. for (let j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
  267. if (intersectionLEs[j].point === event.point) {
  268. indexLE = j;
  269. break;
  270. }
  271. }
  272. if (indexLE !== null) {
  273. const intersectionLE = intersectionLEs.splice(indexLE)[0];
  274. const ringEvents = events.splice(intersectionLE.index);
  275. ringEvents.unshift(ringEvents[0].otherSE);
  276. ringsOut.push(new _RingOut(ringEvents.reverse()));
  277. continue;
  278. }
  279. intersectionLEs.push({
  280. index: events.length,
  281. point: event.point
  282. });
  283. const comparator = event.getLeftmostComparator(prevEvent);
  284. nextEvent = availableLEs.sort(comparator)[0].otherSE;
  285. break;
  286. }
  287. }
  288. ringsOut.push(new _RingOut(events));
  289. }
  290. return ringsOut;
  291. }
  292. constructor(events) {
  293. this.events = events;
  294. for (let i = 0, iMax = events.length; i < iMax; i++) {
  295. events[i].segment.ringOut = this;
  296. }
  297. this.poly = null;
  298. }
  299. getGeom() {
  300. let prevPt = this.events[0].point;
  301. const points = [prevPt];
  302. for (let i = 1, iMax = this.events.length - 1; i < iMax; i++) {
  303. const pt2 = this.events[i].point;
  304. const nextPt2 = this.events[i + 1].point;
  305. if (precision.orient(pt2, prevPt, nextPt2) === 0) continue;
  306. points.push(pt2);
  307. prevPt = pt2;
  308. }
  309. if (points.length === 1) return null;
  310. const pt = points[0];
  311. const nextPt = points[1];
  312. if (precision.orient(pt, prevPt, nextPt) === 0) points.shift();
  313. points.push(points[0]);
  314. const step = this.isExteriorRing() ? 1 : -1;
  315. const iStart = this.isExteriorRing() ? 0 : points.length - 1;
  316. const iEnd = this.isExteriorRing() ? points.length : -1;
  317. const orderedPoints = [];
  318. for (let i = iStart; i != iEnd; i += step)
  319. orderedPoints.push([points[i].x.toNumber(), points[i].y.toNumber()]);
  320. return orderedPoints;
  321. }
  322. isExteriorRing() {
  323. if (this._isExteriorRing === void 0) {
  324. const enclosing = this.enclosingRing();
  325. this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
  326. }
  327. return this._isExteriorRing;
  328. }
  329. enclosingRing() {
  330. if (this._enclosingRing === void 0) {
  331. this._enclosingRing = this._calcEnclosingRing();
  332. }
  333. return this._enclosingRing;
  334. }
  335. /* Returns the ring that encloses this one, if any */
  336. _calcEnclosingRing() {
  337. let leftMostEvt = this.events[0];
  338. for (let i = 1, iMax = this.events.length; i < iMax; i++) {
  339. const evt = this.events[i];
  340. if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
  341. }
  342. let prevSeg = leftMostEvt.segment.prevInResult();
  343. let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
  344. while (true) {
  345. if (!prevSeg) return null;
  346. if (!prevPrevSeg) return prevSeg.ringOut;
  347. if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
  348. if (prevPrevSeg.ringOut?.enclosingRing() !== prevSeg.ringOut) {
  349. return prevSeg.ringOut;
  350. } else return prevSeg.ringOut?.enclosingRing();
  351. }
  352. prevSeg = prevPrevSeg.prevInResult();
  353. prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
  354. }
  355. }
  356. };
  357. var PolyOut = class {
  358. exteriorRing;
  359. interiorRings;
  360. constructor(exteriorRing) {
  361. this.exteriorRing = exteriorRing;
  362. exteriorRing.poly = this;
  363. this.interiorRings = [];
  364. }
  365. addInterior(ring) {
  366. this.interiorRings.push(ring);
  367. ring.poly = this;
  368. }
  369. getGeom() {
  370. const geom0 = this.exteriorRing.getGeom();
  371. if (geom0 === null) return null;
  372. const geom = [geom0];
  373. for (let i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
  374. const ringGeom = this.interiorRings[i].getGeom();
  375. if (ringGeom === null) continue;
  376. geom.push(ringGeom);
  377. }
  378. return geom;
  379. }
  380. };
  381. var MultiPolyOut = class {
  382. rings;
  383. polys;
  384. constructor(rings) {
  385. this.rings = rings;
  386. this.polys = this._composePolys(rings);
  387. }
  388. getGeom() {
  389. const geom = [];
  390. for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
  391. const polyGeom = this.polys[i].getGeom();
  392. if (polyGeom === null) continue;
  393. geom.push(polyGeom);
  394. }
  395. return geom;
  396. }
  397. _composePolys(rings) {
  398. const polys = [];
  399. for (let i = 0, iMax = rings.length; i < iMax; i++) {
  400. const ring = rings[i];
  401. if (ring.poly) continue;
  402. if (ring.isExteriorRing()) polys.push(new PolyOut(ring));
  403. else {
  404. const enclosingRing = ring.enclosingRing();
  405. if (!enclosingRing?.poly) polys.push(new PolyOut(enclosingRing));
  406. enclosingRing?.poly?.addInterior(ring);
  407. }
  408. }
  409. return polys;
  410. }
  411. };
  412. // src/sweep-line.ts
  413. import { SplayTreeSet as SplayTreeSet2 } from "splaytree-ts";
  414. var SweepLine = class {
  415. queue;
  416. tree;
  417. segments;
  418. constructor(queue, comparator = Segment.compare) {
  419. this.queue = queue;
  420. this.tree = new SplayTreeSet2(comparator);
  421. this.segments = [];
  422. }
  423. process(event) {
  424. const segment = event.segment;
  425. const newEvents = [];
  426. if (event.consumedBy) {
  427. if (event.isLeft) this.queue.delete(event.otherSE);
  428. else this.tree.delete(segment);
  429. return newEvents;
  430. }
  431. if (event.isLeft) this.tree.add(segment);
  432. let prevSeg = segment;
  433. let nextSeg = segment;
  434. do {
  435. prevSeg = this.tree.lastBefore(prevSeg);
  436. } while (prevSeg != null && prevSeg.consumedBy != void 0);
  437. do {
  438. nextSeg = this.tree.firstAfter(nextSeg);
  439. } while (nextSeg != null && nextSeg.consumedBy != void 0);
  440. if (event.isLeft) {
  441. let prevMySplitter = null;
  442. if (prevSeg) {
  443. const prevInter = prevSeg.getIntersection(segment);
  444. if (prevInter !== null) {
  445. if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
  446. if (!prevSeg.isAnEndpoint(prevInter)) {
  447. const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
  448. for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  449. newEvents.push(newEventsFromSplit[i]);
  450. }
  451. }
  452. }
  453. }
  454. let nextMySplitter = null;
  455. if (nextSeg) {
  456. const nextInter = nextSeg.getIntersection(segment);
  457. if (nextInter !== null) {
  458. if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
  459. if (!nextSeg.isAnEndpoint(nextInter)) {
  460. const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
  461. for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  462. newEvents.push(newEventsFromSplit[i]);
  463. }
  464. }
  465. }
  466. }
  467. if (prevMySplitter !== null || nextMySplitter !== null) {
  468. let mySplitter = null;
  469. if (prevMySplitter === null) mySplitter = nextMySplitter;
  470. else if (nextMySplitter === null) mySplitter = prevMySplitter;
  471. else {
  472. const cmpSplitters = SweepEvent.comparePoints(
  473. prevMySplitter,
  474. nextMySplitter
  475. );
  476. mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
  477. }
  478. this.queue.delete(segment.rightSE);
  479. newEvents.push(segment.rightSE);
  480. const newEventsFromSplit = segment.split(mySplitter);
  481. for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  482. newEvents.push(newEventsFromSplit[i]);
  483. }
  484. }
  485. if (newEvents.length > 0) {
  486. this.tree.delete(segment);
  487. newEvents.push(event);
  488. } else {
  489. this.segments.push(segment);
  490. segment.prev = prevSeg;
  491. }
  492. } else {
  493. if (prevSeg && nextSeg) {
  494. const inter = prevSeg.getIntersection(nextSeg);
  495. if (inter !== null) {
  496. if (!prevSeg.isAnEndpoint(inter)) {
  497. const newEventsFromSplit = this._splitSafely(prevSeg, inter);
  498. for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  499. newEvents.push(newEventsFromSplit[i]);
  500. }
  501. }
  502. if (!nextSeg.isAnEndpoint(inter)) {
  503. const newEventsFromSplit = this._splitSafely(nextSeg, inter);
  504. for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
  505. newEvents.push(newEventsFromSplit[i]);
  506. }
  507. }
  508. }
  509. }
  510. this.tree.delete(segment);
  511. }
  512. return newEvents;
  513. }
  514. /* Safely split a segment that is currently in the datastructures
  515. * IE - a segment other than the one that is currently being processed. */
  516. _splitSafely(seg, pt) {
  517. this.tree.delete(seg);
  518. const rightSE = seg.rightSE;
  519. this.queue.delete(rightSE);
  520. const newEvents = seg.split(pt);
  521. newEvents.push(rightSE);
  522. if (seg.consumedBy === void 0) this.tree.add(seg);
  523. return newEvents;
  524. }
  525. };
  526. // src/operation.ts
  527. var Operation = class {
  528. type;
  529. numMultiPolys;
  530. run(type, geom, moreGeoms) {
  531. operation.type = type;
  532. const multipolys = [new MultiPolyIn(geom, true)];
  533. for (let i = 0, iMax = moreGeoms.length; i < iMax; i++) {
  534. multipolys.push(new MultiPolyIn(moreGeoms[i], false));
  535. }
  536. operation.numMultiPolys = multipolys.length;
  537. if (operation.type === "difference") {
  538. const subject = multipolys[0];
  539. let i = 1;
  540. while (i < multipolys.length) {
  541. if (getBboxOverlap(multipolys[i].bbox, subject.bbox) !== null) i++;
  542. else multipolys.splice(i, 1);
  543. }
  544. }
  545. if (operation.type === "intersection") {
  546. for (let i = 0, iMax = multipolys.length; i < iMax; i++) {
  547. const mpA = multipolys[i];
  548. for (let j = i + 1, jMax = multipolys.length; j < jMax; j++) {
  549. if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
  550. }
  551. }
  552. }
  553. const queue = new SplayTreeSet3(SweepEvent.compare);
  554. for (let i = 0, iMax = multipolys.length; i < iMax; i++) {
  555. const sweepEvents = multipolys[i].getSweepEvents();
  556. for (let j = 0, jMax = sweepEvents.length; j < jMax; j++) {
  557. queue.add(sweepEvents[j]);
  558. }
  559. }
  560. const sweepLine = new SweepLine(queue);
  561. let evt = null;
  562. if (queue.size != 0) {
  563. evt = queue.first();
  564. queue.delete(evt);
  565. }
  566. while (evt) {
  567. const newEvents = sweepLine.process(evt);
  568. for (let i = 0, iMax = newEvents.length; i < iMax; i++) {
  569. const evt2 = newEvents[i];
  570. if (evt2.consumedBy === void 0) queue.add(evt2);
  571. }
  572. if (queue.size != 0) {
  573. evt = queue.first();
  574. queue.delete(evt);
  575. } else {
  576. evt = null;
  577. }
  578. }
  579. precision.reset();
  580. const ringsOut = RingOut.factory(sweepLine.segments);
  581. const result = new MultiPolyOut(ringsOut);
  582. return result.getGeom();
  583. }
  584. };
  585. var operation = new Operation();
  586. var operation_default = operation;
  587. // src/segment.ts
  588. var segmentId = 0;
  589. var Segment = class _Segment {
  590. id;
  591. leftSE;
  592. rightSE;
  593. rings;
  594. windings;
  595. ringOut;
  596. consumedBy;
  597. prev;
  598. _prevInResult;
  599. _beforeState;
  600. _afterState;
  601. _isInResult;
  602. /* This compare() function is for ordering segments in the sweep
  603. * line tree, and does so according to the following criteria:
  604. *
  605. * Consider the vertical line that lies an infinestimal step to the
  606. * right of the right-more of the two left endpoints of the input
  607. * segments. Imagine slowly moving a point up from negative infinity
  608. * in the increasing y direction. Which of the two segments will that
  609. * point intersect first? That segment comes 'before' the other one.
  610. *
  611. * If neither segment would be intersected by such a line, (if one
  612. * or more of the segments are vertical) then the line to be considered
  613. * is directly on the right-more of the two left inputs.
  614. */
  615. static compare(a, b) {
  616. const alx = a.leftSE.point.x;
  617. const blx = b.leftSE.point.x;
  618. const arx = a.rightSE.point.x;
  619. const brx = b.rightSE.point.x;
  620. if (brx.isLessThan(alx)) return 1;
  621. if (arx.isLessThan(blx)) return -1;
  622. const aly = a.leftSE.point.y;
  623. const bly = b.leftSE.point.y;
  624. const ary = a.rightSE.point.y;
  625. const bry = b.rightSE.point.y;
  626. if (alx.isLessThan(blx)) {
  627. if (bly.isLessThan(aly) && bly.isLessThan(ary)) return 1;
  628. if (bly.isGreaterThan(aly) && bly.isGreaterThan(ary)) return -1;
  629. const aCmpBLeft = a.comparePoint(b.leftSE.point);
  630. if (aCmpBLeft < 0) return 1;
  631. if (aCmpBLeft > 0) return -1;
  632. const bCmpARight = b.comparePoint(a.rightSE.point);
  633. if (bCmpARight !== 0) return bCmpARight;
  634. return -1;
  635. }
  636. if (alx.isGreaterThan(blx)) {
  637. if (aly.isLessThan(bly) && aly.isLessThan(bry)) return -1;
  638. if (aly.isGreaterThan(bly) && aly.isGreaterThan(bry)) return 1;
  639. const bCmpALeft = b.comparePoint(a.leftSE.point);
  640. if (bCmpALeft !== 0) return bCmpALeft;
  641. const aCmpBRight = a.comparePoint(b.rightSE.point);
  642. if (aCmpBRight < 0) return 1;
  643. if (aCmpBRight > 0) return -1;
  644. return 1;
  645. }
  646. if (aly.isLessThan(bly)) return -1;
  647. if (aly.isGreaterThan(bly)) return 1;
  648. if (arx.isLessThan(brx)) {
  649. const bCmpARight = b.comparePoint(a.rightSE.point);
  650. if (bCmpARight !== 0) return bCmpARight;
  651. }
  652. if (arx.isGreaterThan(brx)) {
  653. const aCmpBRight = a.comparePoint(b.rightSE.point);
  654. if (aCmpBRight < 0) return 1;
  655. if (aCmpBRight > 0) return -1;
  656. }
  657. if (!arx.eq(brx)) {
  658. const ay = ary.minus(aly);
  659. const ax = arx.minus(alx);
  660. const by = bry.minus(bly);
  661. const bx = brx.minus(blx);
  662. if (ay.isGreaterThan(ax) && by.isLessThan(bx)) return 1;
  663. if (ay.isLessThan(ax) && by.isGreaterThan(bx)) return -1;
  664. }
  665. if (arx.isGreaterThan(brx)) return 1;
  666. if (arx.isLessThan(brx)) return -1;
  667. if (ary.isLessThan(bry)) return -1;
  668. if (ary.isGreaterThan(bry)) return 1;
  669. if (a.id < b.id) return -1;
  670. if (a.id > b.id) return 1;
  671. return 0;
  672. }
  673. /* Warning: a reference to ringWindings input will be stored,
  674. * and possibly will be later modified */
  675. constructor(leftSE, rightSE, rings, windings) {
  676. this.id = ++segmentId;
  677. this.leftSE = leftSE;
  678. leftSE.segment = this;
  679. leftSE.otherSE = rightSE;
  680. this.rightSE = rightSE;
  681. rightSE.segment = this;
  682. rightSE.otherSE = leftSE;
  683. this.rings = rings;
  684. this.windings = windings;
  685. }
  686. static fromRing(pt1, pt2, ring) {
  687. let leftPt, rightPt, winding;
  688. const cmpPts = SweepEvent.comparePoints(pt1, pt2);
  689. if (cmpPts < 0) {
  690. leftPt = pt1;
  691. rightPt = pt2;
  692. winding = 1;
  693. } else if (cmpPts > 0) {
  694. leftPt = pt2;
  695. rightPt = pt1;
  696. winding = -1;
  697. } else
  698. throw new Error(
  699. `Tried to create degenerate segment at [${pt1.x}, ${pt1.y}]`
  700. );
  701. const leftSE = new SweepEvent(leftPt, true);
  702. const rightSE = new SweepEvent(rightPt, false);
  703. return new _Segment(leftSE, rightSE, [ring], [winding]);
  704. }
  705. /* When a segment is split, the rightSE is replaced with a new sweep event */
  706. replaceRightSE(newRightSE) {
  707. this.rightSE = newRightSE;
  708. this.rightSE.segment = this;
  709. this.rightSE.otherSE = this.leftSE;
  710. this.leftSE.otherSE = this.rightSE;
  711. }
  712. bbox() {
  713. const y1 = this.leftSE.point.y;
  714. const y2 = this.rightSE.point.y;
  715. return {
  716. ll: { x: this.leftSE.point.x, y: y1.isLessThan(y2) ? y1 : y2 },
  717. ur: { x: this.rightSE.point.x, y: y1.isGreaterThan(y2) ? y1 : y2 }
  718. };
  719. }
  720. /* A vector from the left point to the right */
  721. vector() {
  722. return {
  723. x: this.rightSE.point.x.minus(this.leftSE.point.x),
  724. y: this.rightSE.point.y.minus(this.leftSE.point.y)
  725. };
  726. }
  727. isAnEndpoint(pt) {
  728. return pt.x.eq(this.leftSE.point.x) && pt.y.eq(this.leftSE.point.y) || pt.x.eq(this.rightSE.point.x) && pt.y.eq(this.rightSE.point.y);
  729. }
  730. /* Compare this segment with a point.
  731. *
  732. * A point P is considered to be colinear to a segment if there
  733. * exists a distance D such that if we travel along the segment
  734. * from one * endpoint towards the other a distance D, we find
  735. * ourselves at point P.
  736. *
  737. * Return value indicates:
  738. *
  739. * 1: point lies above the segment (to the left of vertical)
  740. * 0: point is colinear to segment
  741. * -1: point lies below the segment (to the right of vertical)
  742. */
  743. comparePoint(point) {
  744. return precision.orient(this.leftSE.point, point, this.rightSE.point);
  745. }
  746. /**
  747. * Given another segment, returns the first non-trivial intersection
  748. * between the two segments (in terms of sweep line ordering), if it exists.
  749. *
  750. * A 'non-trivial' intersection is one that will cause one or both of the
  751. * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
  752. *
  753. * * endpoint of segA with endpoint of segB --> trivial
  754. * * endpoint of segA with point along segB --> non-trivial
  755. * * endpoint of segB with point along segA --> non-trivial
  756. * * point along segA with point along segB --> non-trivial
  757. *
  758. * If no non-trivial intersection exists, return null
  759. * Else, return null.
  760. */
  761. getIntersection(other) {
  762. const tBbox = this.bbox();
  763. const oBbox = other.bbox();
  764. const bboxOverlap = getBboxOverlap(tBbox, oBbox);
  765. if (bboxOverlap === null) return null;
  766. const tlp = this.leftSE.point;
  767. const trp = this.rightSE.point;
  768. const olp = other.leftSE.point;
  769. const orp = other.rightSE.point;
  770. const touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
  771. const touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
  772. const touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
  773. const touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0;
  774. if (touchesThisLSE && touchesOtherLSE) {
  775. if (touchesThisRSE && !touchesOtherRSE) return trp;
  776. if (!touchesThisRSE && touchesOtherRSE) return orp;
  777. return null;
  778. }
  779. if (touchesThisLSE) {
  780. if (touchesOtherRSE) {
  781. if (tlp.x.eq(orp.x) && tlp.y.eq(orp.y)) return null;
  782. }
  783. return tlp;
  784. }
  785. if (touchesOtherLSE) {
  786. if (touchesThisRSE) {
  787. if (trp.x.eq(olp.x) && trp.y.eq(olp.y)) return null;
  788. }
  789. return olp;
  790. }
  791. if (touchesThisRSE && touchesOtherRSE) return null;
  792. if (touchesThisRSE) return trp;
  793. if (touchesOtherRSE) return orp;
  794. const pt = intersection(tlp, this.vector(), olp, other.vector());
  795. if (pt === null) return null;
  796. if (!isInBbox(bboxOverlap, pt)) return null;
  797. return precision.snap(pt);
  798. }
  799. /**
  800. * Split the given segment into multiple segments on the given points.
  801. * * Each existing segment will retain its leftSE and a new rightSE will be
  802. * generated for it.
  803. * * A new segment will be generated which will adopt the original segment's
  804. * rightSE, and a new leftSE will be generated for it.
  805. * * If there are more than two points given to split on, new segments
  806. * in the middle will be generated with new leftSE and rightSE's.
  807. * * An array of the newly generated SweepEvents will be returned.
  808. *
  809. * Warning: input array of points is modified
  810. */
  811. split(point) {
  812. const newEvents = [];
  813. const alreadyLinked = point.events !== void 0;
  814. const newLeftSE = new SweepEvent(point, true);
  815. const newRightSE = new SweepEvent(point, false);
  816. const oldRightSE = this.rightSE;
  817. this.replaceRightSE(newRightSE);
  818. newEvents.push(newRightSE);
  819. newEvents.push(newLeftSE);
  820. const newSeg = new _Segment(
  821. newLeftSE,
  822. oldRightSE,
  823. this.rings.slice(),
  824. this.windings.slice()
  825. );
  826. if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
  827. newSeg.swapEvents();
  828. }
  829. if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
  830. this.swapEvents();
  831. }
  832. if (alreadyLinked) {
  833. newLeftSE.checkForConsuming();
  834. newRightSE.checkForConsuming();
  835. }
  836. return newEvents;
  837. }
  838. /* Swap which event is left and right */
  839. swapEvents() {
  840. const tmpEvt = this.rightSE;
  841. this.rightSE = this.leftSE;
  842. this.leftSE = tmpEvt;
  843. this.leftSE.isLeft = true;
  844. this.rightSE.isLeft = false;
  845. for (let i = 0, iMax = this.windings.length; i < iMax; i++) {
  846. this.windings[i] *= -1;
  847. }
  848. }
  849. /* Consume another segment. We take their rings under our wing
  850. * and mark them as consumed. Use for perfectly overlapping segments */
  851. consume(other) {
  852. let consumer = this;
  853. let consumee = other;
  854. while (consumer.consumedBy) consumer = consumer.consumedBy;
  855. while (consumee.consumedBy) consumee = consumee.consumedBy;
  856. const cmp = _Segment.compare(consumer, consumee);
  857. if (cmp === 0) return;
  858. if (cmp > 0) {
  859. const tmp = consumer;
  860. consumer = consumee;
  861. consumee = tmp;
  862. }
  863. if (consumer.prev === consumee) {
  864. const tmp = consumer;
  865. consumer = consumee;
  866. consumee = tmp;
  867. }
  868. for (let i = 0, iMax = consumee.rings.length; i < iMax; i++) {
  869. const ring = consumee.rings[i];
  870. const winding = consumee.windings[i];
  871. const index = consumer.rings.indexOf(ring);
  872. if (index === -1) {
  873. consumer.rings.push(ring);
  874. consumer.windings.push(winding);
  875. } else consumer.windings[index] += winding;
  876. }
  877. consumee.rings = null;
  878. consumee.windings = null;
  879. consumee.consumedBy = consumer;
  880. consumee.leftSE.consumedBy = consumer.leftSE;
  881. consumee.rightSE.consumedBy = consumer.rightSE;
  882. }
  883. /* The first segment previous segment chain that is in the result */
  884. prevInResult() {
  885. if (this._prevInResult !== void 0) return this._prevInResult;
  886. if (!this.prev) this._prevInResult = null;
  887. else if (this.prev.isInResult()) this._prevInResult = this.prev;
  888. else this._prevInResult = this.prev.prevInResult();
  889. return this._prevInResult;
  890. }
  891. beforeState() {
  892. if (this._beforeState !== void 0) return this._beforeState;
  893. if (!this.prev)
  894. this._beforeState = {
  895. rings: [],
  896. windings: [],
  897. multiPolys: []
  898. };
  899. else {
  900. const seg = this.prev.consumedBy || this.prev;
  901. this._beforeState = seg.afterState();
  902. }
  903. return this._beforeState;
  904. }
  905. afterState() {
  906. if (this._afterState !== void 0) return this._afterState;
  907. const beforeState = this.beforeState();
  908. this._afterState = {
  909. rings: beforeState.rings.slice(0),
  910. windings: beforeState.windings.slice(0),
  911. multiPolys: []
  912. };
  913. const ringsAfter = this._afterState.rings;
  914. const windingsAfter = this._afterState.windings;
  915. const mpsAfter = this._afterState.multiPolys;
  916. for (let i = 0, iMax = this.rings.length; i < iMax; i++) {
  917. const ring = this.rings[i];
  918. const winding = this.windings[i];
  919. const index = ringsAfter.indexOf(ring);
  920. if (index === -1) {
  921. ringsAfter.push(ring);
  922. windingsAfter.push(winding);
  923. } else windingsAfter[index] += winding;
  924. }
  925. const polysAfter = [];
  926. const polysExclude = [];
  927. for (let i = 0, iMax = ringsAfter.length; i < iMax; i++) {
  928. if (windingsAfter[i] === 0) continue;
  929. const ring = ringsAfter[i];
  930. const poly = ring.poly;
  931. if (polysExclude.indexOf(poly) !== -1) continue;
  932. if (ring.isExterior) polysAfter.push(poly);
  933. else {
  934. if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
  935. const index = polysAfter.indexOf(ring.poly);
  936. if (index !== -1) polysAfter.splice(index, 1);
  937. }
  938. }
  939. for (let i = 0, iMax = polysAfter.length; i < iMax; i++) {
  940. const mp = polysAfter[i].multiPoly;
  941. if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
  942. }
  943. return this._afterState;
  944. }
  945. /* Is this segment part of the final result? */
  946. isInResult() {
  947. if (this.consumedBy) return false;
  948. if (this._isInResult !== void 0) return this._isInResult;
  949. const mpsBefore = this.beforeState().multiPolys;
  950. const mpsAfter = this.afterState().multiPolys;
  951. switch (operation_default.type) {
  952. case "union": {
  953. const noBefores = mpsBefore.length === 0;
  954. const noAfters = mpsAfter.length === 0;
  955. this._isInResult = noBefores !== noAfters;
  956. break;
  957. }
  958. case "intersection": {
  959. let least;
  960. let most;
  961. if (mpsBefore.length < mpsAfter.length) {
  962. least = mpsBefore.length;
  963. most = mpsAfter.length;
  964. } else {
  965. least = mpsAfter.length;
  966. most = mpsBefore.length;
  967. }
  968. this._isInResult = most === operation_default.numMultiPolys && least < most;
  969. break;
  970. }
  971. case "xor": {
  972. const diff = Math.abs(mpsBefore.length - mpsAfter.length);
  973. this._isInResult = diff % 2 === 1;
  974. break;
  975. }
  976. case "difference": {
  977. const isJustSubject = (mps) => mps.length === 1 && mps[0].isSubject;
  978. this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
  979. break;
  980. }
  981. }
  982. return this._isInResult;
  983. }
  984. };
  985. // src/geom-in.ts
  986. var RingIn = class {
  987. poly;
  988. isExterior;
  989. segments;
  990. bbox;
  991. constructor(geomRing, poly, isExterior) {
  992. if (!Array.isArray(geomRing) || geomRing.length === 0) {
  993. throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
  994. }
  995. this.poly = poly;
  996. this.isExterior = isExterior;
  997. this.segments = [];
  998. if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
  999. throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
  1000. }
  1001. const firstPoint = precision.snap({ x: new BigNumber2(geomRing[0][0]), y: new BigNumber2(geomRing[0][1]) });
  1002. this.bbox = {
  1003. ll: { x: firstPoint.x, y: firstPoint.y },
  1004. ur: { x: firstPoint.x, y: firstPoint.y }
  1005. };
  1006. let prevPoint = firstPoint;
  1007. for (let i = 1, iMax = geomRing.length; i < iMax; i++) {
  1008. if (typeof geomRing[i][0] !== "number" || typeof geomRing[i][1] !== "number") {
  1009. throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
  1010. }
  1011. const point = precision.snap({ x: new BigNumber2(geomRing[i][0]), y: new BigNumber2(geomRing[i][1]) });
  1012. if (point.x.eq(prevPoint.x) && point.y.eq(prevPoint.y)) continue;
  1013. this.segments.push(Segment.fromRing(prevPoint, point, this));
  1014. if (point.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = point.x;
  1015. if (point.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = point.y;
  1016. if (point.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = point.x;
  1017. if (point.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = point.y;
  1018. prevPoint = point;
  1019. }
  1020. if (!firstPoint.x.eq(prevPoint.x) || !firstPoint.y.eq(prevPoint.y)) {
  1021. this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
  1022. }
  1023. }
  1024. getSweepEvents() {
  1025. const sweepEvents = [];
  1026. for (let i = 0, iMax = this.segments.length; i < iMax; i++) {
  1027. const segment = this.segments[i];
  1028. sweepEvents.push(segment.leftSE);
  1029. sweepEvents.push(segment.rightSE);
  1030. }
  1031. return sweepEvents;
  1032. }
  1033. };
  1034. var PolyIn = class {
  1035. multiPoly;
  1036. exteriorRing;
  1037. interiorRings;
  1038. bbox;
  1039. constructor(geomPoly, multiPoly) {
  1040. if (!Array.isArray(geomPoly)) {
  1041. throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
  1042. }
  1043. this.exteriorRing = new RingIn(geomPoly[0], this, true);
  1044. this.bbox = {
  1045. ll: { x: this.exteriorRing.bbox.ll.x, y: this.exteriorRing.bbox.ll.y },
  1046. ur: { x: this.exteriorRing.bbox.ur.x, y: this.exteriorRing.bbox.ur.y }
  1047. };
  1048. this.interiorRings = [];
  1049. for (let i = 1, iMax = geomPoly.length; i < iMax; i++) {
  1050. const ring = new RingIn(geomPoly[i], this, false);
  1051. if (ring.bbox.ll.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = ring.bbox.ll.x;
  1052. if (ring.bbox.ll.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = ring.bbox.ll.y;
  1053. if (ring.bbox.ur.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = ring.bbox.ur.x;
  1054. if (ring.bbox.ur.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = ring.bbox.ur.y;
  1055. this.interiorRings.push(ring);
  1056. }
  1057. this.multiPoly = multiPoly;
  1058. }
  1059. getSweepEvents() {
  1060. const sweepEvents = this.exteriorRing.getSweepEvents();
  1061. for (let i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
  1062. const ringSweepEvents = this.interiorRings[i].getSweepEvents();
  1063. for (let j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
  1064. sweepEvents.push(ringSweepEvents[j]);
  1065. }
  1066. }
  1067. return sweepEvents;
  1068. }
  1069. };
  1070. var MultiPolyIn = class {
  1071. isSubject;
  1072. polys;
  1073. bbox;
  1074. constructor(geom, isSubject) {
  1075. if (!Array.isArray(geom)) {
  1076. throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
  1077. }
  1078. try {
  1079. if (typeof geom[0][0][0] === "number") geom = [geom];
  1080. } catch (ex) {
  1081. }
  1082. this.polys = [];
  1083. this.bbox = {
  1084. ll: { x: new BigNumber2(Number.POSITIVE_INFINITY), y: new BigNumber2(Number.POSITIVE_INFINITY) },
  1085. ur: { x: new BigNumber2(Number.NEGATIVE_INFINITY), y: new BigNumber2(Number.NEGATIVE_INFINITY) }
  1086. };
  1087. for (let i = 0, iMax = geom.length; i < iMax; i++) {
  1088. const poly = new PolyIn(geom[i], this);
  1089. if (poly.bbox.ll.x.isLessThan(this.bbox.ll.x)) this.bbox.ll.x = poly.bbox.ll.x;
  1090. if (poly.bbox.ll.y.isLessThan(this.bbox.ll.y)) this.bbox.ll.y = poly.bbox.ll.y;
  1091. if (poly.bbox.ur.x.isGreaterThan(this.bbox.ur.x)) this.bbox.ur.x = poly.bbox.ur.x;
  1092. if (poly.bbox.ur.y.isGreaterThan(this.bbox.ur.y)) this.bbox.ur.y = poly.bbox.ur.y;
  1093. this.polys.push(poly);
  1094. }
  1095. this.isSubject = isSubject;
  1096. }
  1097. getSweepEvents() {
  1098. const sweepEvents = [];
  1099. for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
  1100. const polySweepEvents = this.polys[i].getSweepEvents();
  1101. for (let j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
  1102. sweepEvents.push(polySweepEvents[j]);
  1103. }
  1104. }
  1105. return sweepEvents;
  1106. }
  1107. };
  1108. // src/index.ts
  1109. var union = (geom, ...moreGeoms) => operation_default.run("union", geom, moreGeoms);
  1110. var intersection2 = (geom, ...moreGeoms) => operation_default.run("intersection", geom, moreGeoms);
  1111. var xor = (geom, ...moreGeoms) => operation_default.run("xor", geom, moreGeoms);
  1112. var difference = (geom, ...moreGeoms) => operation_default.run("difference", geom, moreGeoms);
  1113. var setPrecision = precision.set;
  1114. export {
  1115. difference,
  1116. intersection2 as intersection,
  1117. setPrecision,
  1118. union,
  1119. xor
  1120. };
  1121. //# sourceMappingURL=index.js.map