'use strict' var bsearch = require('binary-search-bounds') var orient = require('robust-orientation')[3] var EVENT_POINT = 0 var EVENT_END = 1 var EVENT_START = 2 module.exports = monotoneTriangulate //A partial convex hull fragment, made of two unimonotone polygons function PartialHull(a, b, idx, lowerIds, upperIds) { this.a = a this.b = b this.idx = idx this.lowerIds = lowerIds this.upperIds = upperIds } //An event in the sweep line procedure function Event(a, b, type, idx) { this.a = a this.b = b this.type = type this.idx = idx } //This is used to compare events for the sweep line procedure // Points are: // 1. sorted lexicographically // 2. sorted by type (point < end < start) // 3. segments sorted by winding order // 4. sorted by index function compareEvent(a, b) { var d = (a.a[0] - b.a[0]) || (a.a[1] - b.a[1]) || (a.type - b.type) if(d) { return d } if(a.type !== EVENT_POINT) { d = orient(a.a, a.b, b.b) if(d) { return d } } return a.idx - b.idx } function testPoint(hull, p) { return orient(hull.a, hull.b, p) } function addPoint(cells, hulls, points, p, idx) { var lo = bsearch.lt(hulls, p, testPoint) var hi = bsearch.gt(hulls, p, testPoint) for(var i=lo; i 1 && orient( points[lowerIds[m-2]], points[lowerIds[m-1]], p) > 0) { cells.push( [lowerIds[m-1], lowerIds[m-2], idx]) m -= 1 } lowerIds.length = m lowerIds.push(idx) //Insert p into upper hull var upperIds = hull.upperIds var m = upperIds.length while(m > 1 && orient( points[upperIds[m-2]], points[upperIds[m-1]], p) < 0) { cells.push( [upperIds[m-2], upperIds[m-1], idx]) m -= 1 } upperIds.length = m upperIds.push(idx) } } function findSplit(hull, edge) { var d if(hull.a[0] < edge.a[0]) { d = orient(hull.a, hull.b, edge.a) } else { d = orient(edge.b, edge.a, hull.a) } if(d) { return d } if(edge.b[0] < hull.b[0]) { d = orient(hull.a, hull.b, edge.b) } else { d = orient(edge.b, edge.a, hull.b) } return d || hull.idx - edge.idx } function splitHulls(hulls, points, event) { var splitIdx = bsearch.le(hulls, event, findSplit) var hull = hulls[splitIdx] var upperIds = hull.upperIds var x = upperIds[upperIds.length-1] hull.upperIds = [x] hulls.splice(splitIdx+1, 0, new PartialHull(event.a, event.b, event.idx, [x], upperIds)) } function mergeHulls(hulls, points, event) { //Swap pointers for merge search var tmp = event.a event.a = event.b event.b = tmp var mergeIdx = bsearch.eq(hulls, event, findSplit) var upper = hulls[mergeIdx] var lower = hulls[mergeIdx-1] lower.upperIds = upper.upperIds hulls.splice(mergeIdx, 1) } function monotoneTriangulate(points, edges) { var numPoints = points.length var numEdges = edges.length var events = [] //Create point events for(var i=0; i b[0]) { events.push( new Event(b, a, EVENT_START, i), new Event(a, b, EVENT_END, i)) } } //Sort events events.sort(compareEvent) //Initialize hull var minX = events[0].a[0] - (1 + Math.abs(events[0].a[0])) * Math.pow(2, -52) var hull = [ new PartialHull([minX, 1], [minX, 0], -1, [], [], [], []) ] //Process events in order var cells = [] for(var i=0, numEvents=events.length; i