2
0
Эх сурвалжийг харах

Merge pull request #19115 from Mugen87/dev49

Earcut: Upgrade version.
Mr.doob 5 жил өмнө
parent
commit
09d8662558
1 өөрчлөгдсөн 50 нэмэгдсэн , 16 устгасан
  1. 50 16
      src/extras/Earcut.js

+ 50 - 16
src/extras/Earcut.js

@@ -1,6 +1,6 @@
 /**
 /**
  * @author Mugen87 / https://github.com/Mugen87
  * @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 = {
 var Earcut = {
@@ -156,7 +156,7 @@ function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
 
 
 			} else if ( pass === 1 ) {
 			} else if ( pass === 1 ) {
 
 
-				ear = cureLocalIntersections( ear, triangles, dim );
+				ear = cureLocalIntersections( filterPoints( ear ), triangles, dim );
 				earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
 				earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );
 
 
 				// as a last resort, try splitting the remaining polygon into two
 				// as a last resort, try splitting the remaining polygon into two
@@ -286,7 +286,7 @@ function cureLocalIntersections( start, triangles, dim ) {
 
 
 	} while ( p !== start );
 	} while ( p !== start );
 
 
-	return p;
+	return filterPoints( p );
 
 
 }
 }
 
 
@@ -369,6 +369,9 @@ function eliminateHole( hole, outerNode ) {
 	if ( outerNode ) {
 	if ( outerNode ) {
 
 
 		var b = splitPolygon( outerNode, hole );
 		var b = splitPolygon( outerNode, hole );
+
+		// filter collinear points around the cuts
+		filterPoints( outerNode, outerNode.next );
 		filterPoints( b, b.next );
 		filterPoints( b, b.next );
 
 
 	}
 	}
@@ -413,7 +416,7 @@ function findHoleBridge( hole, outerNode ) {
 
 
 	if ( ! m ) return null;
 	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;
 	// look for points inside the triangle of hole point, segment intersection and endpoint;
 	// if there are no points found, we have a valid connection;
 	// if there are no points found, we have a valid connection;
@@ -425,16 +428,16 @@ function findHoleBridge( hole, outerNode ) {
 		tanMin = Infinity,
 		tanMin = Infinity,
 		tan;
 		tan;
 
 
-	p = m.next;
+	p = m;
 
 
-	while ( p !== stop ) {
+	do {
 
 
 		if ( hx >= p.x && p.x >= mx && hx !== p.x &&
 		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 ) ) {
 				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
 			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;
 				m = p;
 				tanMin = tan;
 				tanMin = tan;
@@ -445,12 +448,19 @@ function findHoleBridge( hole, outerNode ) {
 
 
 		p = p.next;
 		p = p.next;
 
 
-	}
+	} while ( p !== stop );
 
 
 	return m;
 	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
 // interlink polygon nodes in z-order
 function indexCurve( start, minX, minY, invSize ) {
 function indexCurve( start, minX, minY, invSize ) {
 
 
@@ -578,16 +588,18 @@ function getLeftmost( start ) {
 function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
 function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {
 
 
 	return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 &&
 	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)
 // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
 function isValidDiagonal( a, b ) {
 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
 
 
 }
 }
 
 
@@ -608,10 +620,32 @@ function equals( p1, p2 ) {
 // check if two segments intersect
 // check if two segments intersect
 function intersects( p1, q1, p2, q2 ) {
 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;
 
 
 }
 }