Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Earcut: Upgrade version. #19115

Merged
merged 1 commit into from
Apr 12, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 50 additions & 16 deletions src/extras/Earcut.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @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 = {
Expand Down Expand Up @@ -156,7 +156,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
Expand Down Expand Up @@ -286,7 +286,7 @@ function cureLocalIntersections( start, triangles, dim ) {

} while ( p !== start );

return p;
return filterPoints( p );

}

Expand Down Expand Up @@ -369,6 +369,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 );

}
Expand Down Expand Up @@ -413,7 +416,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;
Expand All @@ -425,16 +428,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;
Expand All @@ -445,12 +448,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 ) {

Expand Down Expand Up @@ -578,16 +588,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

}

Expand All @@ -608,10 +620,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;

}

Expand Down