|
@@ -29554,7 +29554,7 @@ TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
|
|
|
|
|
|
/**
|
|
|
* @author Mugen87 / https://github.com/Mugen87
|
|
|
- * Port from https://github.com/mapbox/earcut (v2.1.5)
|
|
|
+ * Port from https://github.com/mapbox/earcut (v2.2.2)
|
|
|
*/
|
|
|
|
|
|
var Earcut = {
|
|
@@ -29710,7 +29710,7 @@ function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
|
|
|
|
|
|
} else if ( pass === 1 ) {
|
|
|
|
|
|
- ear = cureLocalIntersections( ear, triangles, dim );
|
|
|
+ ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
|
|
|
earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
|
|
|
|
|
|
// as a last resort, try splitting the remaining polygon into two
|
|
@@ -29840,7 +29840,7 @@ function cureLocalIntersections( start, triangles, dim ) {
|
|
|
|
|
|
} while ( p !== start );
|
|
|
|
|
|
- return p;
|
|
|
+ return filterPoints( p );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -29923,6 +29923,9 @@ function eliminateHole( hole, outerNode ) {
|
|
|
if ( outerNode ) {
|
|
|
|
|
|
var b = splitPolygon( outerNode, hole );
|
|
|
+
|
|
|
+ // filter collinear points around the cuts
|
|
|
+ filterPoints( outerNode, outerNode.next );
|
|
|
filterPoints( b, b.next );
|
|
|
|
|
|
}
|
|
@@ -29967,7 +29970,7 @@ function findHoleBridge( hole, outerNode ) {
|
|
|
|
|
|
if ( ! m ) return null;
|
|
|
|
|
|
- if ( hx === qx ) return m.prev; // hole touches outer segment; pick lower endpoint
|
|
|
+ if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint
|
|
|
|
|
|
// look for points inside the triangle of hole point, segment intersection and endpoint;
|
|
|
// if there are no points found, we have a valid connection;
|
|
@@ -29979,16 +29982,16 @@ function findHoleBridge( hole, outerNode ) {
|
|
|
tanMin = Infinity,
|
|
|
tan;
|
|
|
|
|
|
- p = m.next;
|
|
|
+ p = m;
|
|
|
|
|
|
- while ( p !== stop ) {
|
|
|
+ do {
|
|
|
|
|
|
if ( hx >= p.x && p.x >= mx && hx !== p.x &&
|
|
|
pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {
|
|
|
|
|
|
tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential
|
|
|
|
|
|
- if ( ( tan < tanMin || ( tan === tanMin && p.x > m.x ) ) && locallyInside( p, hole ) ) {
|
|
|
+ if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {
|
|
|
|
|
|
m = p;
|
|
|
tanMin = tan;
|
|
@@ -29999,12 +30002,19 @@ function findHoleBridge( hole, outerNode ) {
|
|
|
|
|
|
p = p.next;
|
|
|
|
|
|
- }
|
|
|
+ } while ( p !== stop );
|
|
|
|
|
|
return m;
|
|
|
|
|
|
}
|
|
|
|
|
|
+// whether sector in vertex m contains sector in vertex p in the same coordinates
|
|
|
+function sectorContainsSector( m, p ) {
|
|
|
+
|
|
|
+ return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
// interlink polygon nodes in z-order
|
|
|
function indexCurve( start, minX, minY, invSize ) {
|
|
|
|
|
@@ -30132,16 +30142,18 @@ function getLeftmost( start ) {
|
|
|
function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
|
|
|
|
|
|
return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
|
|
|
- ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
|
|
|
- ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
|
|
|
+ ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 &&
|
|
|
+ ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
|
|
|
function isValidDiagonal( a, b ) {
|
|
|
|
|
|
- return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) &&
|
|
|
- locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b );
|
|
|
+ return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges
|
|
|
+ ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible
|
|
|
+ ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors
|
|
|
+ equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case
|
|
|
|
|
|
}
|
|
|
|
|
@@ -30162,10 +30174,32 @@ function equals( p1, p2 ) {
|
|
|
// check if two segments intersect
|
|
|
function intersects( p1, q1, p2, q2 ) {
|
|
|
|
|
|
- if ( ( equals( p1, p2 ) && equals( q1, q2 ) ) ||
|
|
|
- ( equals( p1, q2 ) && equals( p2, q1 ) ) ) return true;
|
|
|
- return area( p1, q1, p2 ) > 0 !== area( p1, q1, q2 ) > 0 &&
|
|
|
- area( p2, q2, p1 ) > 0 !== area( p2, q2, q1 ) > 0;
|
|
|
+ var o1 = sign( area( p1, q1, p2 ) );
|
|
|
+ var o2 = sign( area( p1, q1, q2 ) );
|
|
|
+ var o3 = sign( area( p2, q2, p1 ) );
|
|
|
+ var o4 = sign( area( p2, q2, q1 ) );
|
|
|
+
|
|
|
+ if ( o1 !== o2 && o3 !== o4 ) return true; // general case
|
|
|
+
|
|
|
+ if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
|
|
|
+ if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
|
|
|
+ if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
|
|
|
+ if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
|
|
|
+
|
|
|
+ return false;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// for collinear points p, q, r, check if point q lies on segment pr
|
|
|
+function onSegment( p, q, r ) {
|
|
|
+
|
|
|
+ return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+function sign( num ) {
|
|
|
+
|
|
|
+ return num > 0 ? 1 : num < 0 ? - 1 : 0;
|
|
|
|
|
|
}
|
|
|
|