StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
StackGenVis/frontend/node_modules/slab-decomposition/slabs.js

230 lines
5.5 KiB

"use strict"
module.exports = createSlabDecomposition
var bounds = require("binary-search-bounds")
var createRBTree = require("functional-red-black-tree")
var orient = require("robust-orientation")
var orderSegments = require("./lib/order-segments")
function SlabDecomposition(slabs, coordinates, horizontal) {
this.slabs = slabs
this.coordinates = coordinates
this.horizontal = horizontal
}
var proto = SlabDecomposition.prototype
function compareHorizontal(e, y) {
return e.y - y
}
function searchBucket(root, p) {
var lastNode = null
while(root) {
var seg = root.key
var l, r
if(seg[0][0] < seg[1][0]) {
l = seg[0]
r = seg[1]
} else {
l = seg[1]
r = seg[0]
}
var o = orient(l, r, p)
if(o < 0) {
root = root.left
} else if(o > 0) {
if(p[0] !== seg[1][0]) {
lastNode = root
root = root.right
} else {
var val = searchBucket(root.right, p)
if(val) {
return val
}
root = root.left
}
} else {
if(p[0] !== seg[1][0]) {
return root
} else {
var val = searchBucket(root.right, p)
if(val) {
return val
}
root = root.left
}
}
}
return lastNode
}
proto.castUp = function(p) {
var bucket = bounds.le(this.coordinates, p[0])
if(bucket < 0) {
return -1
}
var root = this.slabs[bucket]
var hitNode = searchBucket(this.slabs[bucket], p)
var lastHit = -1
if(hitNode) {
lastHit = hitNode.value
}
//Edge case: need to handle horizontal segments (sucks)
if(this.coordinates[bucket] === p[0]) {
var lastSegment = null
if(hitNode) {
lastSegment = hitNode.key
}
if(bucket > 0) {
var otherHitNode = searchBucket(this.slabs[bucket-1], p)
if(otherHitNode) {
if(lastSegment) {
if(orderSegments(otherHitNode.key, lastSegment) > 0) {
lastSegment = otherHitNode.key
lastHit = otherHitNode.value
}
} else {
lastHit = otherHitNode.value
lastSegment = otherHitNode.key
}
}
}
var horiz = this.horizontal[bucket]
if(horiz.length > 0) {
var hbucket = bounds.ge(horiz, p[1], compareHorizontal)
if(hbucket < horiz.length) {
var e = horiz[hbucket]
if(p[1] === e.y) {
if(e.closed) {
return e.index
} else {
while(hbucket < horiz.length-1 && horiz[hbucket+1].y === p[1]) {
hbucket = hbucket+1
e = horiz[hbucket]
if(e.closed) {
return e.index
}
}
if(e.y === p[1] && !e.start) {
hbucket = hbucket+1
if(hbucket >= horiz.length) {
return lastHit
}
e = horiz[hbucket]
}
}
}
//Check if e is above/below last segment
if(e.start) {
if(lastSegment) {
var o = orient(lastSegment[0], lastSegment[1], [p[0], e.y])
if(lastSegment[0][0] > lastSegment[1][0]) {
o = -o
}
if(o > 0) {
lastHit = e.index
}
} else {
lastHit = e.index
}
} else if(e.y !== p[1]) {
lastHit = e.index
}
}
}
}
return lastHit
}
function IntervalSegment(y, index, start, closed) {
this.y = y
this.index = index
this.start = start
this.closed = closed
}
function Event(x, segment, create, index) {
this.x = x
this.segment = segment
this.create = create
this.index = index
}
function createSlabDecomposition(segments) {
var numSegments = segments.length
var numEvents = 2 * numSegments
var events = new Array(numEvents)
for(var i=0; i<numSegments; ++i) {
var s = segments[i]
var f = s[0][0] < s[1][0]
events[2*i] = new Event(s[0][0], s, f, i)
events[2*i+1] = new Event(s[1][0], s, !f, i)
}
events.sort(function(a,b) {
var d = a.x - b.x
if(d) {
return d
}
d = a.create - b.create
if(d) {
return d
}
return Math.min(a.segment[0][1], a.segment[1][1]) - Math.min(b.segment[0][1], b.segment[1][1])
})
var tree = createRBTree(orderSegments)
var slabs = []
var lines = []
var horizontal = []
var lastX = -Infinity
for(var i=0; i<numEvents; ) {
var x = events[i].x
var horiz = []
while(i < numEvents) {
var e = events[i]
if(e.x !== x) {
break
}
i += 1
if(e.segment[0][0] === e.x && e.segment[1][0] === e.x) {
if(e.create) {
if(e.segment[0][1] < e.segment[1][1]) {
horiz.push(new IntervalSegment(
e.segment[0][1],
e.index,
true,
true))
horiz.push(new IntervalSegment(
e.segment[1][1],
e.index,
false,
false))
} else {
horiz.push(new IntervalSegment(
e.segment[1][1],
e.index,
true,
false))
horiz.push(new IntervalSegment(
e.segment[0][1],
e.index,
false,
true))
}
}
} else {
if(e.create) {
tree = tree.insert(e.segment, e.index)
} else {
tree = tree.remove(e.segment)
}
}
}
slabs.push(tree.root)
lines.push(x)
horizontal.push(horiz)
}
return new SlabDecomposition(slabs, lines, horizontal)
}