/** * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal * @author Alexander Rose */ export { InterUnitGraph } class InterUnitGraph { /** Number of inter-unit edges */ readonly edgeCount: number /** Array of inter-unit edges */ readonly edges: ReadonlyArray> private readonly edgeKeyIndex: Map private readonly vertexKeyIndex: Map /** Get an array of unit-pair-edges that are connected to the given unit */ getConnectedUnits(unit: Unit): ReadonlyArray> { if (!this.map.has(unit.id)) return emptyArray; return this.map.get(unit.id)!; } /** Index into this.edges */ getEdgeIndex(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): number { const edgeKey = InterUnitGraph.getEdgeKey(indexA, unitA, indexB, unitB) const index = this.edgeKeyIndex.get(edgeKey) return index !== undefined ? index : -1 } /** Check if edge exists */ hasEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): boolean { return this.getEdgeIndex(indexA, unitA, indexB, unitB) !== -1 } /** Get inter-unit edge given a pair of indices and units */ getEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): InterUnitGraph.Edge | undefined { const index = this.getEdgeIndex(indexA, unitA, indexB, unitB) return index !== -1 ? this.edges[index] : undefined } /** Indices into this.edges */ getEdgeIndices(index: VertexIndex, unit: Unit): ReadonlyArray { return this.vertexKeyIndex.get(InterUnitGraph.getVertexKey(index, unit)) || [] } constructor(private map: Map[]>) { let count = 0 const edges: (InterUnitGraph.Edge)[] = [] const edgeKeyIndex = new Map() const elementKeyIndex = new Map() this.map.forEach(pairEdgesArray => { pairEdgesArray.forEach(pairEdges => { count += pairEdges.edgeCount pairEdges.connectedIndices.forEach(indexA => { pairEdges.getEdges(indexA).forEach(edgeInfo => { const { unitA, unitB } = pairEdges const edgeKey = InterUnitGraph.getEdgeKey(indexA, unitA, edgeInfo.indexB, unitB) edgeKeyIndex.set(edgeKey, edges.length) const elementKey = InterUnitGraph.getVertexKey(indexA, unitA) const e = elementKeyIndex.get(elementKey) if (e === undefined) elementKeyIndex.set(elementKey, [edges.length]) else e.push(edges.length) edges.push({ ...edgeInfo, indexA, unitA, unitB }) }) }) }) }) this.edgeCount = count this.edges = edges this.edgeKeyIndex = edgeKeyIndex this.vertexKeyIndex = elementKeyIndex } } namespace InterUnitGraph { export class UnitPairEdges { hasEdges(indexA: VertexIndex) { return this.edgeMap.has(indexA); } getEdges(indexA: VertexIndex): ReadonlyArray> { if (!this.edgeMap.has(indexA)) return emptyArray; return this.edgeMap.get(indexA)!; } get areUnitsOrdered() { return this.unitA.id < this.unitB.id; } constructor(public unitA: Unit, public unitB: Unit, public edgeCount: number, public connectedIndices: ReadonlyArray, private edgeMap: Map[]>) { } } export type UnitBase = { id: number } export type EdgePropsBase = { [name: string]: any } export interface EdgeInfo { /** indexInto */ readonly indexB: VertexIndex, readonly props: EdgeProps } export interface Edge { readonly unitA: Unit, readonly unitB: Unit, readonly indexA: VertexIndex, readonly indexB: VertexIndex, readonly props: EdgeProps } export function getEdgeKey(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit) { return `${indexA}|${unitA.id}|${indexB}|${unitB.id}` } export function getVertexKey(index: VertexIndex, unit: Unit) { return `${index}|${unit.id}` } } const emptyArray: any[] = [];