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.
130 lines
2.8 KiB
130 lines
2.8 KiB
"use strict"
|
|
|
|
module.exports = planarDual
|
|
|
|
var compareAngle = require("compare-angle")
|
|
|
|
function planarDual(cells, positions) {
|
|
|
|
var numVertices = positions.length|0
|
|
var numEdges = cells.length
|
|
var adj = [new Array(numVertices), new Array(numVertices)]
|
|
for(var i=0; i<numVertices; ++i) {
|
|
adj[0][i] = []
|
|
adj[1][i] = []
|
|
}
|
|
for(var i=0; i<numEdges; ++i) {
|
|
var c = cells[i]
|
|
adj[0][c[0]].push(c)
|
|
adj[1][c[1]].push(c)
|
|
}
|
|
|
|
var cycles = []
|
|
|
|
//Add isolated vertices as trivial case
|
|
for(var i=0; i<numVertices; ++i) {
|
|
if(adj[0][i].length + adj[1][i].length === 0) {
|
|
cycles.push( [i] )
|
|
}
|
|
}
|
|
|
|
//Remove a half edge
|
|
function cut(c, i) {
|
|
var a = adj[i][c[i]]
|
|
a.splice(a.indexOf(c), 1)
|
|
}
|
|
|
|
//Find next vertex and cut edge
|
|
function next(a, b, noCut) {
|
|
var nextCell, nextVertex, nextDir
|
|
for(var i=0; i<2; ++i) {
|
|
if(adj[i][b].length > 0) {
|
|
nextCell = adj[i][b][0]
|
|
nextDir = i
|
|
break
|
|
}
|
|
}
|
|
nextVertex = nextCell[nextDir^1]
|
|
|
|
for(var dir=0; dir<2; ++dir) {
|
|
var nbhd = adj[dir][b]
|
|
for(var k=0; k<nbhd.length; ++k) {
|
|
var e = nbhd[k]
|
|
var p = e[dir^1]
|
|
var cmp = compareAngle(
|
|
positions[a],
|
|
positions[b],
|
|
positions[nextVertex],
|
|
positions[p])
|
|
if(cmp > 0) {
|
|
nextCell = e
|
|
nextVertex = p
|
|
nextDir = dir
|
|
}
|
|
}
|
|
}
|
|
if(noCut) {
|
|
return nextVertex
|
|
}
|
|
if(nextCell) {
|
|
cut(nextCell, nextDir)
|
|
}
|
|
return nextVertex
|
|
}
|
|
|
|
function extractCycle(v, dir) {
|
|
var e0 = adj[dir][v][0]
|
|
var cycle = [v]
|
|
cut(e0, dir)
|
|
var u = e0[dir^1]
|
|
var d0 = dir
|
|
while(true) {
|
|
while(u !== v) {
|
|
cycle.push(u)
|
|
u = next(cycle[cycle.length-2], u, false)
|
|
}
|
|
if(adj[0][v].length + adj[1][v].length === 0) {
|
|
break
|
|
}
|
|
var a = cycle[cycle.length-1]
|
|
var b = v
|
|
var c = cycle[1]
|
|
var d = next(a, b, true)
|
|
if(compareAngle(positions[a], positions[b], positions[c], positions[d]) < 0) {
|
|
break
|
|
}
|
|
cycle.push(v)
|
|
u = next(a, b)
|
|
}
|
|
return cycle
|
|
}
|
|
|
|
function shouldGlue(pcycle, ncycle) {
|
|
return (ncycle[1] === ncycle[ncycle.length-1])
|
|
}
|
|
|
|
for(var i=0; i<numVertices; ++i) {
|
|
for(var j=0; j<2; ++j) {
|
|
var pcycle = []
|
|
while(adj[j][i].length > 0) {
|
|
var ni = adj[0][i].length
|
|
var ncycle = extractCycle(i,j)
|
|
if(shouldGlue(pcycle, ncycle)) {
|
|
//Glue together trivial cycles
|
|
pcycle.push.apply(pcycle, ncycle)
|
|
} else {
|
|
if(pcycle.length > 0) {
|
|
cycles.push(pcycle)
|
|
}
|
|
pcycle = ncycle
|
|
}
|
|
}
|
|
if(pcycle.length > 0) {
|
|
cycles.push(pcycle)
|
|
}
|
|
}
|
|
}
|
|
|
|
//Combine paths and loops together
|
|
return cycles
|
|
} |