// This class is used of the case when there are multiple edges, but there is no need to duplicate layers. import {BasicGraph} from '../../structs/BasicGraph' import {GeomNode} from '../core/geomNode' import {Database} from './Database' import {LayerArrays, layersAreCorrect} from './LayerArrays' import {LayerEdge} from './layerEdge' import {LayerInserter} from './LayerInserter' import {PolyIntEdge} from './polyIntEdge' import {ProperLayeredGraph} from './ProperLayeredGraph' // We just insert dummy nodes for edge middles without distorting the order of vertices of the layers. export class EdgePathsInserter { database: Database intGraph: BasicGraph layeredGraph: ProperLayeredGraph virtNodesToIntEdges = new Map() NLayeredGraph: ProperLayeredGraph la: LayerArrays Nla: LayerArrays get NLayering() { return this.Nla.y } static InsertPaths(layeredGraph: ProperLayeredGraph, la: LayerArrays, db: Database, intGraphP: BasicGraph) { const li = new EdgePathsInserter(layeredGraph, la, db, intGraphP) li.InsertPaths() return { layeredGraph: li.NLayeredGraph, la: li.Nla, } } constructor(layeredGraph: ProperLayeredGraph, la: LayerArrays, database: Database, intGraphP: BasicGraph) { this.la = la this.database = database this.layeredGraph = layeredGraph this.intGraph = intGraphP } InsertPaths() { /*Assert.assert(layersAreCorrect(this.la))*/ this.CreateFullLayeredGraph() this.InitNewLayering() this.MapVirtualNodesToEdges() this.WidenOriginalLayers() /*Assert.assert(layersAreCorrect(this.la))*/ } WidenOriginalLayers() { for (let i = 0; i < this.la.Layers.length; i++) { const layer = this.Nla.Layers[i] let offset = 0 for (const v of this.la.Layers[i]) { const e = this.virtNodesToIntEdges.get(v) if (e != null) { const layerOffsetInTheEdge = this.NLayering[e.source] - this.NLayering[v] const list = this.database.Multiedges.get(e.source, e.target) for (const ie of list) { if (!this.EdgeIsFlat(ie)) { if (ie !== e) { const u = ie.LayerEdges[layerOffsetInTheEdge].Source layer[offset] = u this.Nla.x[u] = offset++ } else { layer[offset] = v this.Nla.x[v] = offset++ } } } } else { layer[offset] = v this.Nla.x[v] = offset++ } } } } EdgeIsFlat(ie: PolyIntEdge) { return this.la.y[ie.source] === this.la.y[ie.target] } MapVirtualNodesToEdges() { for (const list of this.database.RegularMultiedges()) for (const e of list) if (!this.EdgeIsFlat(e)) //the edge is not flat for (const le of e.LayerEdges) if (le.Target !== e.target) { this.virtNodesToIntEdges.set(le.Target, e) } } private CreateFullLayeredGraph() { let currentVV = this.layeredGraph.NodeCount for (const [k, list] of this.database.Multiedges.keyValues()) { if (k.x !== k.y) { //not a self edge let first = true let span = 0 for (const e of list) { if (first) { first = false span = e.LayerSpan } else { e.LayerEdges = new Array(span) if (span === 1) e.LayerEdges[0] = new LayerEdge(e.source, e.target, e.CrossingWeight) else { for (let i = 0; i < span; i++) { const bVV = {currentVV: currentVV} const source = EdgePathsInserter.GetSource(bVV, e, i) currentVV = bVV.currentVV const target = EdgePathsInserter.GetTarget(currentVV, e, i, span) e.LayerEdges[i] = new LayerEdge(source, target, e.CrossingWeight) } } } LayerInserter.RegisterDontStepOnVertex(this.database, e) } } } this.NLayeredGraph = new ProperLayeredGraph(this.intGraph) } static GetTarget(currentVV: number, e: PolyIntEdge, i: number, span: number): number { if (i < span - 1) return currentVV return e.target } static GetSource(boxedVV: {currentVV: number}, e: PolyIntEdge, i: number): number { if (i === 0) return e.source return boxedVV.currentVV++ } InitNewLayering() { this.Nla = new LayerArrays(new Array(this.NLayeredGraph.NodeCount)) for (let i = 0; i < this.layeredGraph.NodeCount; i++) this.NLayering[i] = this.la.y[i] for (const [k, list] of this.database.Multiedges.keyValues()) { if (k.x !== k.y && this.la.y[k.x] !== this.la.y[k.y]) { //not a self edge and not a flat edge let layer = 0 let first = true for (const e of list) { if (first) { first = false layer = this.la.y[e.source] } let cl = layer - 1 for (const le of e.LayerEdges) this.NLayering[le.Target] = cl-- } } } // number[][] newLayers = new number[la.Layers.length][]; const newLayers = new Array>(this.la.Layers.length) //count new layer widths const counts = new Array(newLayers.length).fill(0) for (const l of this.NLayering) counts[l]++ for (let i = 0; i < counts.length; i++) newLayers[i] = new Array(counts[i]) this.Nla = new LayerArrays(this.NLayering) this.Nla.Layers = newLayers } }