geojs 1.14.0 → 1.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/geo.js CHANGED
@@ -26745,6 +26745,11 @@ var _quadFeature = function quadFeature(arg) {
26745
26745
  coordbasis.y = 1 - coordbasis.y;
26746
26746
  }
26747
26747
  if (coordbasis) {
26748
+ if (quad.crop && quad.crop.x !== undefined && quad.crop.y !== undefined && (coordbasis.x >= quad.crop.x || coordbasis.y >= quad.crop.y)) {
26749
+ indices.pop();
26750
+ found.pop();
26751
+ return;
26752
+ }
26748
26753
  extra[quad.idx] = {
26749
26754
  basis: coordbasis,
26750
26755
  _quad: quad
@@ -28164,7 +28169,7 @@ module.exports = _sceneObject;
28164
28169
  * @constant
28165
28170
  * @type {string}
28166
28171
  */
28167
- module.exports = "43f61353e44a71f669a4f0d631f102a517605fe9";
28172
+ module.exports = "8e2a6bf94ba85a370a33f2144165d89dd6061439";
28168
28173
 
28169
28174
  /***/ }),
28170
28175
 
@@ -32855,6 +32860,8 @@ var _trackFeature = function trackFeature(arg) {
32855
32860
  highidx = testidx;
32856
32861
  }
32857
32862
  }
32863
+ // todo: if we want non-linear travel between points, we would adjust
32864
+ // fl and fh here
32858
32865
  var fh = (time - lowt) / (hight - lowt),
32859
32866
  fl = 1 - fh;
32860
32867
  return {
@@ -40049,7 +40056,7 @@ module.exports = _vectorFeature;
40049
40056
  * @constant
40050
40057
  * @type {string}
40051
40058
  */
40052
- module.exports = "1.14.0";
40059
+ module.exports = "1.14.2";
40053
40060
 
40054
40061
  /***/ }),
40055
40062
 
@@ -75967,7 +75974,7 @@ module.exports = "/* lineFeature fragment shader */\n\n#ifdef GL_ES\n #ifdef GL
75967
75974
  /***/ 9336:
75968
75975
  /***/ (function(module) {
75969
75976
 
75970
- module.exports = "/* lineFeature vertex shader */\n\n#ifdef GL_ES\n precision highp float;\n#endif\nattribute vec3 pos;\nattribute vec3 prev;\nattribute vec3 next;\nattribute vec3 far;\nattribute float flags;\n\nattribute vec3 strokeColor;\nattribute float strokeOpacity;\nattribute float strokeWidth;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float pixelWidth;\nuniform float aspect;\nuniform float miterLimit;\nuniform float antialiasing;\n\nvarying vec4 strokeColorVar;\nvarying vec4 subpos; /* px, py, length - px, width */\nvarying vec4 info; /* near mode, far mode, offset */\nvarying vec4 angles; /* near angle cos, sin, far angle cos, sin */\n\nconst float PI = 3.14159265358979323846264;\n\nvec4 viewCoord(vec3 c) {\n vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1.0);\n if (result.w != 0.0) result = result / result.w;\n return result;\n}\n\nfloat atan2(float y, float x) {\n if (x > 0.0) return atan(y / x);\n if (x < 0.0 && y >= 0.0) return atan(y / x) + PI;\n if (x < 0.0) return atan(y / x) - PI;\n return sign(y) * 0.5 * PI;\n}\n\nvoid main(void)\n{\n /* If any vertex has been deliberately set to a negative opacity,\n * skip doing computations on it. */\n if (strokeOpacity < 0.0) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n /* convert coordinates. We have four values, since we need to\n * calculate the angles between the lines formed by prev-pos and\n * pos-next, and between pos-next and next-far, plus know the angle\n * (prev)---(pos)---(next)---(far) => A---B---C---D */\n vec4 A = viewCoord(prev);\n vec4 B = viewCoord(pos);\n vec4 C = viewCoord(next);\n vec4 D = viewCoord(far);\n // calculate line segment vector and angle\n vec2 deltaCB = C.xy - B.xy;\n if (deltaCB == vec2(0.0, 0.0)) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);\n // values we need to pass along\n strokeColorVar = vec4(strokeColor, strokeOpacity);\n // extract values from our flags field\n int vertex = int(mod(flags, 4.0));\n int nearMode = int(mod(floor(flags / 4.0), 8.0));\n int farMode = int(mod(floor(flags / 32.0), 8.0));\n // we use 11 bits of the flags for the offset, where -1023 to 1023\n // maps to -1 to 1. The 11 bits are a signed value, so simply\n // selecting the bits will result in an unsigned values that may be\n // greater than 1, in which case we have to subtract appropriately.\n float offset = mod(floor(flags / 256.0), 2048.0) / 1023.0;\n if (offset > 1.0) offset -= 2048.0 / 1023.0;\n // by default, offset by the width and don't extend lines. Later,\n // calculate line extensions based on end cap and end join modes\n float yOffset = strokeWidth + antialiasing;\n if (vertex == 0 || vertex == 2) yOffset *= -1.0;\n yOffset += strokeWidth * offset;\n float xOffset = 0.0;\n // end caps\n if (nearMode == 0) {\n xOffset = antialiasing;\n } else if (nearMode == 1 || nearMode == 2) {\n xOffset = strokeWidth + antialiasing;\n }\n\n // If joining lines, calculate the angles in screen space formed by\n // the near end (A-B-C) and far end (B-C-D), and determine how much\n // space is needed for the particular join.\n // This could be changed: if the lines are not a uniform width and\n // offset, then the functional join angle is not simply half the\n // angle between the two lines, but rather half the angle of the\n // inside edge of the the two lines.\n float cosABC = 1.0, sinABC = 0.0, cosBCD = 1.0, sinBCD = 0.0; // of half angles\n // handle near end\n if (nearMode >= 4) {\n float angleBA = atan2(B.y - A.y, (B.x - A.x) * aspect);\n if (A.xy == B.xy) angleBA = angleCB;\n float angleABC = angleCB - angleBA;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosABC = cos(angleABC); sinABC = sin(angleABC);\n // if this angle is close to flat, pass-through the join\n if (nearMode >= 4 && cosABC > 0.999999) {\n nearMode = 3;\n }\n // miter, miter-clip\n if (nearMode == 4 || nearMode == 7) {\n if (cosABC < 0.000001 || 1.0 / cosABC > miterLimit) {\n if (nearMode == 4) {\n nearMode = 5;\n } else {\n xOffset = miterLimit * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n } else {\n // we add an extra 1.0 to the xOffset to make sure that fragment\n // shader is doing the clipping\n xOffset = abs(sinABC / cosABC) * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing + 1.0;\n nearMode = 4;\n }\n }\n // bevel or round join\n if (nearMode == 5 || nearMode == 6) {\n xOffset = strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n }\n\n // handle far end\n if (farMode >= 4) {\n float angleDC = atan2(D.y - C.y, (D.x - C.x) * aspect);\n if (D.xy == C.xy) angleDC = angleCB;\n float angleBCD = angleDC - angleCB;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);\n // if this angle is close to flat, pass-through the join\n if (farMode >= 4 && cosBCD > 0.999999) {\n farMode = 3;\n }\n // miter, miter-clip\n if (farMode == 4 || farMode == 7) {\n if (cosBCD < 0.000001 || 1.0 / cosBCD > miterLimit) {\n if (farMode == 4) farMode = 5;\n } else {\n farMode = 4;\n }\n }\n }\n\n // compute the location of a vertex to include everything that might\n // need to be rendered\n xOffset *= -1.0;\n gl_Position = vec4(\n B.x + (xOffset * cos(angleCB) - yOffset * sin(angleCB)) * pixelWidth,\n B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,\n B.z, 1.0);\n // store other values needed to determine which pixels to plot.\n float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;\n\n if (vertex == 0 || vertex == 1) {\n subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);\n info = vec4(float(nearMode), float(farMode), offset, 0.0);\n angles = vec4(cosABC, sinABC, cosBCD, sinBCD);\n } else {\n subpos = vec4(lineLength - xOffset, -yOffset, xOffset, strokeWidth);\n info = vec4(float(farMode), float(nearMode), -offset, 0.0);\n angles = vec4(cosBCD, -sinBCD, cosABC, -sinABC);\n }\n}\n"
75977
+ module.exports = "/* lineFeature vertex shader */\n\n#ifdef GL_ES\n precision highp float;\n#endif\nattribute vec3 pos;\nattribute vec3 prev;\nattribute vec3 next;\nattribute vec3 far;\nattribute float flags;\n\nattribute vec3 strokeColor;\nattribute float strokeOpacity;\nattribute float strokeWidth;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float pixelWidth;\nuniform float aspect;\nuniform float miterLimit;\nuniform float antialiasing;\n\nvarying vec4 strokeColorVar;\nvarying vec4 subpos; /* px, py, length - px, width */\nvarying vec4 info; /* near mode, far mode, offset */\nvarying vec4 angles; /* near angle cos, sin, far angle cos, sin */\n\nconst float PI = 3.14159265358979323846264;\n\nvec4 viewCoord(vec3 c) {\n vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1.0);\n if (result.w != 0.0) result = result / result.w;\n return result;\n}\n\nfloat atan2(float y, float x) {\n if (x > 0.0) return atan(y / x);\n if (x < 0.0 && y >= 0.0) return atan(y / x) + PI;\n if (x < 0.0) return atan(y / x) - PI;\n return sign(y) * 0.5 * PI;\n}\n\nvoid main(void)\n{\n /* If any vertex has been deliberately set to a negative opacity,\n * skip doing computations on it. */\n if (strokeOpacity < 0.0) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n /* convert coordinates. We have four values, since we need to\n * calculate the angles between the lines formed by prev-pos and\n * pos-next, and between pos-next and next-far, plus know the angle\n * (prev)---(pos)---(next)---(far) => A---B---C---D */\n vec4 A = viewCoord(prev);\n vec4 B = viewCoord(pos);\n vec4 C = viewCoord(next);\n vec4 D = viewCoord(far);\n // calculate line segment vector and angle\n vec2 deltaCB = C.xy - B.xy;\n if (deltaCB == vec2(0.0, 0.0)) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;\n // if lines reverse upon themselves and are not nearly the same length, skip\n // joins. This is a heuristic; the correct method would to be to pass some\n // sort of length of the adjacent line to the fragment renderer and adjust\n // which fragments are rendered, but this is much more complex.\n float abLimit = length(vec2(A.x - B.x, (A.y - B.y) / aspect)) / pixelWidth;\n float dcLimit = length(vec2(D.x - C.x, (D.y - C.y) / aspect)) / pixelWidth;\n if (abLimit >= lineLength - antialiasing - strokeWidth * 0.5 && abLimit <= lineLength + antialiasing + strokeWidth * 0.5) {\n abLimit = 0.0001;\n } else {\n if (abLimit < lineLength) abLimit = lineLength;\n abLimit = (strokeWidth - antialiasing) / (abLimit + antialiasing);\n if (abLimit < 0.0001) abLimit = 0.0001;\n if (abLimit > 0.1) abLimit = 0.1;\n }\n if (dcLimit >= lineLength - antialiasing - strokeWidth * 0.5 && dcLimit <= lineLength + antialiasing + strokeWidth * 0.5) {\n dcLimit = 0.0001;\n } else {\n if (dcLimit < lineLength) dcLimit = lineLength;\n dcLimit = (strokeWidth - antialiasing) / (dcLimit + antialiasing);\n if (dcLimit < 0.0001) dcLimit = 0.0001;\n if (dcLimit > 0.1) dcLimit = 0.1;\n }\n float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);\n // values we need to pass along\n strokeColorVar = vec4(strokeColor, strokeOpacity);\n // extract values from our flags field\n int vertex = int(mod(flags, 4.0));\n int nearMode = int(mod(floor(flags / 4.0), 8.0));\n int farMode = int(mod(floor(flags / 32.0), 8.0));\n // we use 11 bits of the flags for the offset, where -1023 to 1023\n // maps to -1 to 1. The 11 bits are a signed value, so simply\n // selecting the bits will result in an unsigned values that may be\n // greater than 1, in which case we have to subtract appropriately.\n float offset = mod(floor(flags / 256.0), 2048.0) / 1023.0;\n if (offset > 1.0) offset -= 2048.0 / 1023.0;\n // by default, offset by the width and don't extend lines. Later,\n // calculate line extensions based on end cap and end join modes\n float yOffset = strokeWidth + antialiasing;\n if (vertex == 0) yOffset *= -1.0;\n yOffset += strokeWidth * offset;\n float xOffset = 0.0;\n // end caps\n if (nearMode == 0) {\n xOffset = antialiasing;\n } else if (nearMode == 1 || nearMode == 2) {\n xOffset = strokeWidth + antialiasing;\n }\n\n // If joining lines, calculate the angles in screen space formed by\n // the near end (A-B-C) and far end (B-C-D), and determine how much\n // space is needed for the particular join.\n // This could be changed: if the lines are not a uniform width and\n // offset, then the functional join angle is not simply half the\n // angle between the two lines, but rather half the angle of the\n // inside edge of the the two lines.\n float cosABC = 1.0, sinABC = 0.0, cosBCD = 1.0, sinBCD = 0.0; // of half angles\n // handle near end\n if (nearMode >= 4) {\n float angleBA = atan2(B.y - A.y, (B.x - A.x) * aspect);\n if (A.xy == B.xy) angleBA = angleCB;\n float angleABC = angleCB - angleBA;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosABC = cos(angleABC); sinABC = sin(angleABC);\n // if this angle is close to flat, pass-through the join\n if (nearMode >= 4 && (cosABC > 0.999999 || cosABC < abLimit)) {\n nearMode = 3;\n }\n // miter, miter-clip\n if (nearMode == 4 || nearMode == 7) {\n if (cosABC < 0.000001 || 1.0 / cosABC > miterLimit) {\n if (nearMode == 4) {\n nearMode = 5;\n } else {\n xOffset = miterLimit * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n } else {\n // we add an extra 1.0 to the xOffset to make sure that fragment\n // shader is doing the clipping\n xOffset = abs(sinABC / cosABC) * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing + 1.0;\n nearMode = 4;\n }\n }\n // bevel or round join\n if (nearMode == 5 || nearMode == 6) {\n xOffset = strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n }\n\n // handle far end\n if (farMode >= 4) {\n float angleDC = atan2(D.y - C.y, (D.x - C.x) * aspect);\n if (D.xy == C.xy) angleDC = angleCB;\n float angleBCD = angleDC - angleCB;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);\n // if this angle is close to flat, pass-through the join\n if (farMode >= 4 && (cosBCD > 0.999999 || cosBCD < dcLimit)) {\n farMode = 3;\n }\n // miter, miter-clip\n if (farMode == 4 || farMode == 7) {\n if (cosBCD < 0.000001 || 1.0 / cosBCD > miterLimit) {\n if (farMode == 4) farMode = 5;\n } else {\n farMode = 4;\n }\n }\n }\n\n // compute the location of a vertex to include everything that might\n // need to be rendered\n xOffset *= -1.0;\n gl_Position = vec4(\n B.x + (xOffset * cos(angleCB) - yOffset * sin(angleCB)) * pixelWidth,\n B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,\n B.z, 1.0);\n // store other values needed to determine which pixels to plot.\n if (vertex == 0 || vertex == 1) {\n subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);\n info = vec4(float(nearMode), float(farMode), offset, 0.0);\n angles = vec4(cosABC, sinABC, cosBCD, sinBCD);\n } else {\n subpos = vec4(lineLength - xOffset, -yOffset, xOffset, strokeWidth);\n info = vec4(float(farMode), float(nearMode), -offset, 0.0);\n angles = vec4(cosBCD, -sinBCD, cosABC, -sinABC);\n }\n}\n"
75971
75978
 
75972
75979
  /***/ }),
75973
75980
 
@@ -76675,14 +76682,14 @@ function isEar(ear) {
76675
76682
  by = b.y,
76676
76683
  cy = c.y;
76677
76684
 
76678
- // triangle bbox; min & max are calculated like this for speed
76679
- var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
76680
- y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
76681
- x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
76682
- y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
76685
+ // triangle bbox
76686
+ var x0 = Math.min(ax, bx, cx),
76687
+ y0 = Math.min(ay, by, cy),
76688
+ x1 = Math.max(ax, bx, cx),
76689
+ y1 = Math.max(ay, by, cy);
76683
76690
  var p = c.next;
76684
76691
  while (p !== a) {
76685
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76692
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76686
76693
  p = p.next;
76687
76694
  }
76688
76695
  return true;
@@ -76700,11 +76707,11 @@ function isEarHashed(ear, minX, minY, invSize) {
76700
76707
  by = b.y,
76701
76708
  cy = c.y;
76702
76709
 
76703
- // triangle bbox; min & max are calculated like this for speed
76704
- var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
76705
- y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
76706
- x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
76707
- y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
76710
+ // triangle bbox
76711
+ var x0 = Math.min(ax, bx, cx),
76712
+ y0 = Math.min(ay, by, cy),
76713
+ x1 = Math.max(ax, bx, cx),
76714
+ y1 = Math.max(ay, by, cy);
76708
76715
 
76709
76716
  // z-order range for the current triangle bbox;
76710
76717
  var minZ = zOrder(x0, y0, minX, minY, invSize),
@@ -76714,21 +76721,21 @@ function isEarHashed(ear, minX, minY, invSize) {
76714
76721
 
76715
76722
  // look for points inside the triangle in both directions
76716
76723
  while (p && p.z >= minZ && n && n.z <= maxZ) {
76717
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76724
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76718
76725
  p = p.prevZ;
76719
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
76726
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
76720
76727
  n = n.nextZ;
76721
76728
  }
76722
76729
 
76723
76730
  // look for remaining points in decreasing z-order
76724
76731
  while (p && p.z >= minZ) {
76725
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76732
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
76726
76733
  p = p.prevZ;
76727
76734
  }
76728
76735
 
76729
76736
  // look for remaining points in increasing z-order
76730
76737
  while (n && n.z <= maxZ) {
76731
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
76738
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
76732
76739
  n = n.nextZ;
76733
76740
  }
76734
76741
  return true;
@@ -76789,7 +76796,7 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
76789
76796
  if (list === list.next) list.steiner = true;
76790
76797
  queue.push(getLeftmost(list));
76791
76798
  }
76792
- queue.sort(compareX);
76799
+ queue.sort(compareXYSlope);
76793
76800
 
76794
76801
  // process holes from left to right
76795
76802
  for (var _i2 = 0; _i2 < queue.length; _i2++) {
@@ -76797,8 +76804,19 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
76797
76804
  }
76798
76805
  return outerNode;
76799
76806
  }
76800
- function compareX(a, b) {
76801
- return a.x - b.x;
76807
+ function compareXYSlope(a, b) {
76808
+ var result = a.x - b.x;
76809
+ // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find
76810
+ // the bridge to the outer shell is always the point that they meet at.
76811
+ if (result === 0) {
76812
+ result = a.y - b.y;
76813
+ if (result === 0) {
76814
+ var aSlope = (a.next.y - a.y) / (a.next.x - a.x);
76815
+ var bSlope = (b.next.y - b.y) / (b.next.x - b.x);
76816
+ result = aSlope - bSlope;
76817
+ }
76818
+ }
76819
+ return result;
76802
76820
  }
76803
76821
 
76804
76822
  // find a bridge between vertices that connects hole with an outer ring and and link it
@@ -76824,8 +76842,10 @@ function findHoleBridge(hole, outerNode) {
76824
76842
 
76825
76843
  // find a segment intersected by a ray from the hole's leftmost point to the left;
76826
76844
  // segment's endpoint with lesser x will be potential connection point
76845
+ // unless they intersect at a vertex, then choose the vertex
76846
+ if (equals(hole, p)) return p;
76827
76847
  do {
76828
- if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
76848
+ if (equals(hole, p.next)) return p.next;else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
76829
76849
  var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
76830
76850
  if (x <= hx && x > qx) {
76831
76851
  qx = x;
@@ -76954,6 +76974,11 @@ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
76954
76974
  return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
76955
76975
  }
76956
76976
 
76977
+ // check if a point lies within a convex triangle but false if its equal to the first point of the triangle
76978
+ function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
76979
+ return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
76980
+ }
76981
+
76957
76982
  // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
76958
76983
  function isValidDiagonal(a, b) {
76959
76984
  return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && (
package/geo.lean.js CHANGED
@@ -23744,6 +23744,11 @@ var _quadFeature = function quadFeature(arg) {
23744
23744
  coordbasis.y = 1 - coordbasis.y;
23745
23745
  }
23746
23746
  if (coordbasis) {
23747
+ if (quad.crop && quad.crop.x !== undefined && quad.crop.y !== undefined && (coordbasis.x >= quad.crop.x || coordbasis.y >= quad.crop.y)) {
23748
+ indices.pop();
23749
+ found.pop();
23750
+ return;
23751
+ }
23747
23752
  extra[quad.idx] = {
23748
23753
  basis: coordbasis,
23749
23754
  _quad: quad
@@ -25163,7 +25168,7 @@ module.exports = _sceneObject;
25163
25168
  * @constant
25164
25169
  * @type {string}
25165
25170
  */
25166
- module.exports = "43f61353e44a71f669a4f0d631f102a517605fe9";
25171
+ module.exports = "8e2a6bf94ba85a370a33f2144165d89dd6061439";
25167
25172
 
25168
25173
  /***/ }),
25169
25174
 
@@ -29854,6 +29859,8 @@ var _trackFeature = function trackFeature(arg) {
29854
29859
  highidx = testidx;
29855
29860
  }
29856
29861
  }
29862
+ // todo: if we want non-linear travel between points, we would adjust
29863
+ // fl and fh here
29857
29864
  var fh = (time - lowt) / (hight - lowt),
29858
29865
  fl = 1 - fh;
29859
29866
  return {
@@ -37048,7 +37055,7 @@ module.exports = _vectorFeature;
37048
37055
  * @constant
37049
37056
  * @type {string}
37050
37057
  */
37051
- module.exports = "1.14.0";
37058
+ module.exports = "1.14.2";
37052
37059
 
37053
37060
  /***/ }),
37054
37061
 
@@ -72966,7 +72973,7 @@ module.exports = "/* lineFeature fragment shader */\n\n#ifdef GL_ES\n #ifdef GL
72966
72973
  /***/ 9336:
72967
72974
  /***/ (function(module) {
72968
72975
 
72969
- module.exports = "/* lineFeature vertex shader */\n\n#ifdef GL_ES\n precision highp float;\n#endif\nattribute vec3 pos;\nattribute vec3 prev;\nattribute vec3 next;\nattribute vec3 far;\nattribute float flags;\n\nattribute vec3 strokeColor;\nattribute float strokeOpacity;\nattribute float strokeWidth;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float pixelWidth;\nuniform float aspect;\nuniform float miterLimit;\nuniform float antialiasing;\n\nvarying vec4 strokeColorVar;\nvarying vec4 subpos; /* px, py, length - px, width */\nvarying vec4 info; /* near mode, far mode, offset */\nvarying vec4 angles; /* near angle cos, sin, far angle cos, sin */\n\nconst float PI = 3.14159265358979323846264;\n\nvec4 viewCoord(vec3 c) {\n vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1.0);\n if (result.w != 0.0) result = result / result.w;\n return result;\n}\n\nfloat atan2(float y, float x) {\n if (x > 0.0) return atan(y / x);\n if (x < 0.0 && y >= 0.0) return atan(y / x) + PI;\n if (x < 0.0) return atan(y / x) - PI;\n return sign(y) * 0.5 * PI;\n}\n\nvoid main(void)\n{\n /* If any vertex has been deliberately set to a negative opacity,\n * skip doing computations on it. */\n if (strokeOpacity < 0.0) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n /* convert coordinates. We have four values, since we need to\n * calculate the angles between the lines formed by prev-pos and\n * pos-next, and between pos-next and next-far, plus know the angle\n * (prev)---(pos)---(next)---(far) => A---B---C---D */\n vec4 A = viewCoord(prev);\n vec4 B = viewCoord(pos);\n vec4 C = viewCoord(next);\n vec4 D = viewCoord(far);\n // calculate line segment vector and angle\n vec2 deltaCB = C.xy - B.xy;\n if (deltaCB == vec2(0.0, 0.0)) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);\n // values we need to pass along\n strokeColorVar = vec4(strokeColor, strokeOpacity);\n // extract values from our flags field\n int vertex = int(mod(flags, 4.0));\n int nearMode = int(mod(floor(flags / 4.0), 8.0));\n int farMode = int(mod(floor(flags / 32.0), 8.0));\n // we use 11 bits of the flags for the offset, where -1023 to 1023\n // maps to -1 to 1. The 11 bits are a signed value, so simply\n // selecting the bits will result in an unsigned values that may be\n // greater than 1, in which case we have to subtract appropriately.\n float offset = mod(floor(flags / 256.0), 2048.0) / 1023.0;\n if (offset > 1.0) offset -= 2048.0 / 1023.0;\n // by default, offset by the width and don't extend lines. Later,\n // calculate line extensions based on end cap and end join modes\n float yOffset = strokeWidth + antialiasing;\n if (vertex == 0 || vertex == 2) yOffset *= -1.0;\n yOffset += strokeWidth * offset;\n float xOffset = 0.0;\n // end caps\n if (nearMode == 0) {\n xOffset = antialiasing;\n } else if (nearMode == 1 || nearMode == 2) {\n xOffset = strokeWidth + antialiasing;\n }\n\n // If joining lines, calculate the angles in screen space formed by\n // the near end (A-B-C) and far end (B-C-D), and determine how much\n // space is needed for the particular join.\n // This could be changed: if the lines are not a uniform width and\n // offset, then the functional join angle is not simply half the\n // angle between the two lines, but rather half the angle of the\n // inside edge of the the two lines.\n float cosABC = 1.0, sinABC = 0.0, cosBCD = 1.0, sinBCD = 0.0; // of half angles\n // handle near end\n if (nearMode >= 4) {\n float angleBA = atan2(B.y - A.y, (B.x - A.x) * aspect);\n if (A.xy == B.xy) angleBA = angleCB;\n float angleABC = angleCB - angleBA;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosABC = cos(angleABC); sinABC = sin(angleABC);\n // if this angle is close to flat, pass-through the join\n if (nearMode >= 4 && cosABC > 0.999999) {\n nearMode = 3;\n }\n // miter, miter-clip\n if (nearMode == 4 || nearMode == 7) {\n if (cosABC < 0.000001 || 1.0 / cosABC > miterLimit) {\n if (nearMode == 4) {\n nearMode = 5;\n } else {\n xOffset = miterLimit * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n } else {\n // we add an extra 1.0 to the xOffset to make sure that fragment\n // shader is doing the clipping\n xOffset = abs(sinABC / cosABC) * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing + 1.0;\n nearMode = 4;\n }\n }\n // bevel or round join\n if (nearMode == 5 || nearMode == 6) {\n xOffset = strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n }\n\n // handle far end\n if (farMode >= 4) {\n float angleDC = atan2(D.y - C.y, (D.x - C.x) * aspect);\n if (D.xy == C.xy) angleDC = angleCB;\n float angleBCD = angleDC - angleCB;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);\n // if this angle is close to flat, pass-through the join\n if (farMode >= 4 && cosBCD > 0.999999) {\n farMode = 3;\n }\n // miter, miter-clip\n if (farMode == 4 || farMode == 7) {\n if (cosBCD < 0.000001 || 1.0 / cosBCD > miterLimit) {\n if (farMode == 4) farMode = 5;\n } else {\n farMode = 4;\n }\n }\n }\n\n // compute the location of a vertex to include everything that might\n // need to be rendered\n xOffset *= -1.0;\n gl_Position = vec4(\n B.x + (xOffset * cos(angleCB) - yOffset * sin(angleCB)) * pixelWidth,\n B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,\n B.z, 1.0);\n // store other values needed to determine which pixels to plot.\n float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;\n\n if (vertex == 0 || vertex == 1) {\n subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);\n info = vec4(float(nearMode), float(farMode), offset, 0.0);\n angles = vec4(cosABC, sinABC, cosBCD, sinBCD);\n } else {\n subpos = vec4(lineLength - xOffset, -yOffset, xOffset, strokeWidth);\n info = vec4(float(farMode), float(nearMode), -offset, 0.0);\n angles = vec4(cosBCD, -sinBCD, cosABC, -sinABC);\n }\n}\n"
72976
+ module.exports = "/* lineFeature vertex shader */\n\n#ifdef GL_ES\n precision highp float;\n#endif\nattribute vec3 pos;\nattribute vec3 prev;\nattribute vec3 next;\nattribute vec3 far;\nattribute float flags;\n\nattribute vec3 strokeColor;\nattribute float strokeOpacity;\nattribute float strokeWidth;\n\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform float pixelWidth;\nuniform float aspect;\nuniform float miterLimit;\nuniform float antialiasing;\n\nvarying vec4 strokeColorVar;\nvarying vec4 subpos; /* px, py, length - px, width */\nvarying vec4 info; /* near mode, far mode, offset */\nvarying vec4 angles; /* near angle cos, sin, far angle cos, sin */\n\nconst float PI = 3.14159265358979323846264;\n\nvec4 viewCoord(vec3 c) {\n vec4 result = projectionMatrix * modelViewMatrix * vec4(c.xyz, 1.0);\n if (result.w != 0.0) result = result / result.w;\n return result;\n}\n\nfloat atan2(float y, float x) {\n if (x > 0.0) return atan(y / x);\n if (x < 0.0 && y >= 0.0) return atan(y / x) + PI;\n if (x < 0.0) return atan(y / x) - PI;\n return sign(y) * 0.5 * PI;\n}\n\nvoid main(void)\n{\n /* If any vertex has been deliberately set to a negative opacity,\n * skip doing computations on it. */\n if (strokeOpacity < 0.0) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n /* convert coordinates. We have four values, since we need to\n * calculate the angles between the lines formed by prev-pos and\n * pos-next, and between pos-next and next-far, plus know the angle\n * (prev)---(pos)---(next)---(far) => A---B---C---D */\n vec4 A = viewCoord(prev);\n vec4 B = viewCoord(pos);\n vec4 C = viewCoord(next);\n vec4 D = viewCoord(far);\n // calculate line segment vector and angle\n vec2 deltaCB = C.xy - B.xy;\n if (deltaCB == vec2(0.0, 0.0)) {\n gl_Position = vec4(2.0, 2.0, 0.0, 1.0);\n return;\n }\n float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;\n // if lines reverse upon themselves and are not nearly the same length, skip\n // joins. This is a heuristic; the correct method would to be to pass some\n // sort of length of the adjacent line to the fragment renderer and adjust\n // which fragments are rendered, but this is much more complex.\n float abLimit = length(vec2(A.x - B.x, (A.y - B.y) / aspect)) / pixelWidth;\n float dcLimit = length(vec2(D.x - C.x, (D.y - C.y) / aspect)) / pixelWidth;\n if (abLimit >= lineLength - antialiasing - strokeWidth * 0.5 && abLimit <= lineLength + antialiasing + strokeWidth * 0.5) {\n abLimit = 0.0001;\n } else {\n if (abLimit < lineLength) abLimit = lineLength;\n abLimit = (strokeWidth - antialiasing) / (abLimit + antialiasing);\n if (abLimit < 0.0001) abLimit = 0.0001;\n if (abLimit > 0.1) abLimit = 0.1;\n }\n if (dcLimit >= lineLength - antialiasing - strokeWidth * 0.5 && dcLimit <= lineLength + antialiasing + strokeWidth * 0.5) {\n dcLimit = 0.0001;\n } else {\n if (dcLimit < lineLength) dcLimit = lineLength;\n dcLimit = (strokeWidth - antialiasing) / (dcLimit + antialiasing);\n if (dcLimit < 0.0001) dcLimit = 0.0001;\n if (dcLimit > 0.1) dcLimit = 0.1;\n }\n float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);\n // values we need to pass along\n strokeColorVar = vec4(strokeColor, strokeOpacity);\n // extract values from our flags field\n int vertex = int(mod(flags, 4.0));\n int nearMode = int(mod(floor(flags / 4.0), 8.0));\n int farMode = int(mod(floor(flags / 32.0), 8.0));\n // we use 11 bits of the flags for the offset, where -1023 to 1023\n // maps to -1 to 1. The 11 bits are a signed value, so simply\n // selecting the bits will result in an unsigned values that may be\n // greater than 1, in which case we have to subtract appropriately.\n float offset = mod(floor(flags / 256.0), 2048.0) / 1023.0;\n if (offset > 1.0) offset -= 2048.0 / 1023.0;\n // by default, offset by the width and don't extend lines. Later,\n // calculate line extensions based on end cap and end join modes\n float yOffset = strokeWidth + antialiasing;\n if (vertex == 0) yOffset *= -1.0;\n yOffset += strokeWidth * offset;\n float xOffset = 0.0;\n // end caps\n if (nearMode == 0) {\n xOffset = antialiasing;\n } else if (nearMode == 1 || nearMode == 2) {\n xOffset = strokeWidth + antialiasing;\n }\n\n // If joining lines, calculate the angles in screen space formed by\n // the near end (A-B-C) and far end (B-C-D), and determine how much\n // space is needed for the particular join.\n // This could be changed: if the lines are not a uniform width and\n // offset, then the functional join angle is not simply half the\n // angle between the two lines, but rather half the angle of the\n // inside edge of the the two lines.\n float cosABC = 1.0, sinABC = 0.0, cosBCD = 1.0, sinBCD = 0.0; // of half angles\n // handle near end\n if (nearMode >= 4) {\n float angleBA = atan2(B.y - A.y, (B.x - A.x) * aspect);\n if (A.xy == B.xy) angleBA = angleCB;\n float angleABC = angleCB - angleBA;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosABC = cos(angleABC); sinABC = sin(angleABC);\n // if this angle is close to flat, pass-through the join\n if (nearMode >= 4 && (cosABC > 0.999999 || cosABC < abLimit)) {\n nearMode = 3;\n }\n // miter, miter-clip\n if (nearMode == 4 || nearMode == 7) {\n if (cosABC < 0.000001 || 1.0 / cosABC > miterLimit) {\n if (nearMode == 4) {\n nearMode = 5;\n } else {\n xOffset = miterLimit * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n } else {\n // we add an extra 1.0 to the xOffset to make sure that fragment\n // shader is doing the clipping\n xOffset = abs(sinABC / cosABC) * strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing + 1.0;\n nearMode = 4;\n }\n }\n // bevel or round join\n if (nearMode == 5 || nearMode == 6) {\n xOffset = strokeWidth * (1.0 - offset * sign(sinABC)) + antialiasing;\n }\n }\n\n // handle far end\n if (farMode >= 4) {\n float angleDC = atan2(D.y - C.y, (D.x - C.x) * aspect);\n if (D.xy == C.xy) angleDC = angleCB;\n float angleBCD = angleDC - angleCB;\n // ensure angle is in the range [-PI, PI], then take the half angle\n angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;\n cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);\n // if this angle is close to flat, pass-through the join\n if (farMode >= 4 && (cosBCD > 0.999999 || cosBCD < dcLimit)) {\n farMode = 3;\n }\n // miter, miter-clip\n if (farMode == 4 || farMode == 7) {\n if (cosBCD < 0.000001 || 1.0 / cosBCD > miterLimit) {\n if (farMode == 4) farMode = 5;\n } else {\n farMode = 4;\n }\n }\n }\n\n // compute the location of a vertex to include everything that might\n // need to be rendered\n xOffset *= -1.0;\n gl_Position = vec4(\n B.x + (xOffset * cos(angleCB) - yOffset * sin(angleCB)) * pixelWidth,\n B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,\n B.z, 1.0);\n // store other values needed to determine which pixels to plot.\n if (vertex == 0 || vertex == 1) {\n subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);\n info = vec4(float(nearMode), float(farMode), offset, 0.0);\n angles = vec4(cosABC, sinABC, cosBCD, sinBCD);\n } else {\n subpos = vec4(lineLength - xOffset, -yOffset, xOffset, strokeWidth);\n info = vec4(float(farMode), float(nearMode), -offset, 0.0);\n angles = vec4(cosBCD, -sinBCD, cosABC, -sinABC);\n }\n}\n"
72970
72977
 
72971
72978
  /***/ }),
72972
72979
 
@@ -73694,14 +73701,14 @@ function isEar(ear) {
73694
73701
  by = b.y,
73695
73702
  cy = c.y;
73696
73703
 
73697
- // triangle bbox; min & max are calculated like this for speed
73698
- var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
73699
- y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
73700
- x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
73701
- y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
73704
+ // triangle bbox
73705
+ var x0 = Math.min(ax, bx, cx),
73706
+ y0 = Math.min(ay, by, cy),
73707
+ x1 = Math.max(ax, bx, cx),
73708
+ y1 = Math.max(ay, by, cy);
73702
73709
  var p = c.next;
73703
73710
  while (p !== a) {
73704
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73711
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73705
73712
  p = p.next;
73706
73713
  }
73707
73714
  return true;
@@ -73719,11 +73726,11 @@ function isEarHashed(ear, minX, minY, invSize) {
73719
73726
  by = b.y,
73720
73727
  cy = c.y;
73721
73728
 
73722
- // triangle bbox; min & max are calculated like this for speed
73723
- var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
73724
- y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
73725
- x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
73726
- y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
73729
+ // triangle bbox
73730
+ var x0 = Math.min(ax, bx, cx),
73731
+ y0 = Math.min(ay, by, cy),
73732
+ x1 = Math.max(ax, bx, cx),
73733
+ y1 = Math.max(ay, by, cy);
73727
73734
 
73728
73735
  // z-order range for the current triangle bbox;
73729
73736
  var minZ = zOrder(x0, y0, minX, minY, invSize),
@@ -73733,21 +73740,21 @@ function isEarHashed(ear, minX, minY, invSize) {
73733
73740
 
73734
73741
  // look for points inside the triangle in both directions
73735
73742
  while (p && p.z >= minZ && n && n.z <= maxZ) {
73736
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73743
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73737
73744
  p = p.prevZ;
73738
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
73745
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
73739
73746
  n = n.nextZ;
73740
73747
  }
73741
73748
 
73742
73749
  // look for remaining points in decreasing z-order
73743
73750
  while (p && p.z >= minZ) {
73744
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73751
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
73745
73752
  p = p.prevZ;
73746
73753
  }
73747
73754
 
73748
73755
  // look for remaining points in increasing z-order
73749
73756
  while (n && n.z <= maxZ) {
73750
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
73757
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
73751
73758
  n = n.nextZ;
73752
73759
  }
73753
73760
  return true;
@@ -73808,7 +73815,7 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
73808
73815
  if (list === list.next) list.steiner = true;
73809
73816
  queue.push(getLeftmost(list));
73810
73817
  }
73811
- queue.sort(compareX);
73818
+ queue.sort(compareXYSlope);
73812
73819
 
73813
73820
  // process holes from left to right
73814
73821
  for (var _i2 = 0; _i2 < queue.length; _i2++) {
@@ -73816,8 +73823,19 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
73816
73823
  }
73817
73824
  return outerNode;
73818
73825
  }
73819
- function compareX(a, b) {
73820
- return a.x - b.x;
73826
+ function compareXYSlope(a, b) {
73827
+ var result = a.x - b.x;
73828
+ // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find
73829
+ // the bridge to the outer shell is always the point that they meet at.
73830
+ if (result === 0) {
73831
+ result = a.y - b.y;
73832
+ if (result === 0) {
73833
+ var aSlope = (a.next.y - a.y) / (a.next.x - a.x);
73834
+ var bSlope = (b.next.y - b.y) / (b.next.x - b.x);
73835
+ result = aSlope - bSlope;
73836
+ }
73837
+ }
73838
+ return result;
73821
73839
  }
73822
73840
 
73823
73841
  // find a bridge between vertices that connects hole with an outer ring and and link it
@@ -73843,8 +73861,10 @@ function findHoleBridge(hole, outerNode) {
73843
73861
 
73844
73862
  // find a segment intersected by a ray from the hole's leftmost point to the left;
73845
73863
  // segment's endpoint with lesser x will be potential connection point
73864
+ // unless they intersect at a vertex, then choose the vertex
73865
+ if (equals(hole, p)) return p;
73846
73866
  do {
73847
- if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
73867
+ if (equals(hole, p.next)) return p.next;else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
73848
73868
  var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
73849
73869
  if (x <= hx && x > qx) {
73850
73870
  qx = x;
@@ -73973,6 +73993,11 @@ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
73973
73993
  return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
73974
73994
  }
73975
73995
 
73996
+ // check if a point lies within a convex triangle but false if its equal to the first point of the triangle
73997
+ function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
73998
+ return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
73999
+ }
74000
+
73976
74001
  // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
73977
74002
  function isValidDiagonal(a, b) {
73978
74003
  return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && (