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/planar-graph-to-polyline/pg2pl.js

204 lines
4.6 KiB

'use strict'
module.exports = planarGraphToPolyline
var e2a = require('edges-to-adjacency-list')
var planarDual = require('planar-dual')
var preprocessPolygon = require('point-in-big-polygon')
var twoProduct = require('two-product')
var robustSum = require('robust-sum')
var uniq = require('uniq')
var trimLeaves = require('./lib/trim-leaves')
function makeArray(length, fill) {
var result = new Array(length)
for(var i=0; i<length; ++i) {
result[i] = fill
}
return result
}
function makeArrayOfArrays(length) {
var result = new Array(length)
for(var i=0; i<length; ++i) {
result[i] = []
}
return result
}
function planarGraphToPolyline(edges, positions) {
//Trim leaves
var result = trimLeaves(edges, positions)
edges = result[0]
positions = result[1]
var numVertices = positions.length
var numEdges = edges.length
//Calculate adjacency list, check manifold
var adj = e2a(edges, positions.length)
for(var i=0; i<numVertices; ++i) {
if(adj[i].length % 2 === 1) {
throw new Error('planar-graph-to-polyline: graph must be manifold')
}
}
//Get faces
var faces = planarDual(edges, positions)
//Check orientation of a polygon using exact arithmetic
function ccw(c) {
var n = c.length
var area = [0]
for(var j=0; j<n; ++j) {
var a = positions[c[j]]
var b = positions[c[(j+1)%n]]
var t00 = twoProduct(-a[0], a[1])
var t01 = twoProduct(-a[0], b[1])
var t10 = twoProduct( b[0], a[1])
var t11 = twoProduct( b[0], b[1])
area = robustSum(area, robustSum(robustSum(t00, t01), robustSum(t10, t11)))
}
return area[area.length-1] > 0
}
//Extract all clockwise faces
faces = faces.filter(ccw)
//Detect which loops are contained in one another to handle parent-of relation
var numFaces = faces.length
var parent = new Array(numFaces)
var containment = new Array(numFaces)
for(var i=0; i<numFaces; ++i) {
parent[i] = i
var row = new Array(numFaces)
var loopVertices = faces[i].map(function(v) {
return positions[v]
})
var pmc = preprocessPolygon([loopVertices])
var count = 0
outer:
for(var j=0; j<numFaces; ++j) {
row[j] = 0
if(i === j) {
continue
}
var c = faces[j]
var n = c.length
for(var k=0; k<n; ++k) {
var d = pmc(positions[c[k]])
if(d !== 0) {
if(d < 0) {
row[j] = 1
count += 1
}
continue outer
}
}
row[j] = 1
count += 1
}
containment[i] = [count, i, row]
}
containment.sort(function(a,b) {
return b[0] - a[0]
})
for(var i=0; i<numFaces; ++i) {
var row = containment[i]
var idx = row[1]
var children = row[2]
for(var j=0; j<numFaces; ++j) {
if(children[j]) {
parent[j] = idx
}
}
}
//Initialize face adjacency list
var fadj = makeArrayOfArrays(numFaces)
for(var i=0; i<numFaces; ++i) {
fadj[i].push(parent[i])
fadj[parent[i]].push(i)
}
//Build adjacency matrix for edges
var edgeAdjacency = {}
var internalVertices = makeArray(numVertices, false)
for(var i=0; i<numFaces; ++i) {
var c = faces[i]
var n = c.length
for(var j=0; j<n; ++j) {
var a = c[j]
var b = c[(j+1)%n]
var key = Math.min(a,b) + ":" + Math.max(a,b)
if(key in edgeAdjacency) {
var neighbor = edgeAdjacency[key]
fadj[neighbor].push(i)
fadj[i].push(neighbor)
internalVertices[a] = internalVertices[b] = true
} else {
edgeAdjacency[key] = i
}
}
}
function sharedBoundary(c) {
var n = c.length
for(var i=0; i<n; ++i) {
if(!internalVertices[c[i]]) {
return false
}
}
return true
}
var toVisit = []
var parity = makeArray(numFaces, -1)
for(var i=0; i<numFaces; ++i) {
if(parent[i] === i && !sharedBoundary(faces[i])) {
toVisit.push(i)
parity[i] = 0
} else {
parity[i] = -1
}
}
//Using face adjacency, classify faces as in/out
var result = []
while(toVisit.length > 0) {
var top = toVisit.pop()
var nbhd = fadj[top]
uniq(nbhd, function(a,b) {
return a-b
})
var nnbhr = nbhd.length
var p = parity[top]
var polyline
if(p === 0) {
var c = faces[top]
polyline = [c]
}
for(var i=0; i<nnbhr; ++i) {
var f = nbhd[i]
if(parity[f] >= 0) {
continue
}
parity[f] = p^1
toVisit.push(f)
if(p === 0) {
var c = faces[f]
if(!sharedBoundary(c)) {
c.reverse()
polyline.push(c)
}
}
}
if(p === 0) {
result.push(polyline)
}
}
return result
}