inter-unit-graph.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /**
  2. * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. export { InterUnitGraph }
  8. class InterUnitGraph<Unit extends InterUnitGraph.UnitBase, VertexIndex extends number, EdgeProps extends InterUnitGraph.EdgePropsBase = {}> {
  9. /** Number of inter-unit edges */
  10. readonly edgeCount: number
  11. /** Array of inter-unit edges */
  12. readonly edges: ReadonlyArray<InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps>>
  13. private readonly edgeKeyIndex: Map<string, number>
  14. private readonly vertexKeyIndex: Map<string, number[]>
  15. /** Get an array of unit-pair-edges that are connected to the given unit */
  16. getConnectedUnits(unit: Unit): ReadonlyArray<InterUnitGraph.UnitPairEdges<Unit, VertexIndex, EdgeProps>> {
  17. if (!this.map.has(unit.id)) return emptyArray;
  18. return this.map.get(unit.id)!;
  19. }
  20. /** Index into this.edges */
  21. getEdgeIndex(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): number {
  22. const edgeKey = InterUnitGraph.getEdgeKey<Unit, VertexIndex>(indexA, unitA, indexB, unitB)
  23. const index = this.edgeKeyIndex.get(edgeKey)
  24. return index !== undefined ? index : -1
  25. }
  26. /** Check if edge exists */
  27. hasEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): boolean {
  28. return this.getEdgeIndex(indexA, unitA, indexB, unitB) !== -1
  29. }
  30. /** Get inter-unit edge given a pair of indices and units */
  31. getEdge(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit): InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps> | undefined {
  32. const index = this.getEdgeIndex(indexA, unitA, indexB, unitB)
  33. return index !== -1 ? this.edges[index] : undefined
  34. }
  35. /** Indices into this.edges */
  36. getEdgeIndices(index: VertexIndex, unit: Unit): ReadonlyArray<number> {
  37. return this.vertexKeyIndex.get(InterUnitGraph.getVertexKey(index, unit)) || []
  38. }
  39. constructor(private map: Map<number, InterUnitGraph.UnitPairEdges<Unit, VertexIndex, EdgeProps>[]>) {
  40. let count = 0
  41. const edges: (InterUnitGraph.Edge<Unit, VertexIndex, EdgeProps>)[] = []
  42. const edgeKeyIndex = new Map<string, number>()
  43. const elementKeyIndex = new Map<string, number[]>()
  44. this.map.forEach(pairEdgesArray => {
  45. pairEdgesArray.forEach(pairEdges => {
  46. count += pairEdges.edgeCount
  47. pairEdges.connectedIndices.forEach(indexA => {
  48. pairEdges.getEdges(indexA).forEach(edgeInfo => {
  49. const { unitA, unitB } = pairEdges
  50. const edgeKey = InterUnitGraph.getEdgeKey<Unit, VertexIndex>(indexA, unitA, edgeInfo.indexB, unitB)
  51. edgeKeyIndex.set(edgeKey, edges.length)
  52. const elementKey = InterUnitGraph.getVertexKey(indexA, unitA)
  53. const e = elementKeyIndex.get(elementKey)
  54. if (e === undefined) elementKeyIndex.set(elementKey, [edges.length])
  55. else e.push(edges.length)
  56. edges.push({ ...edgeInfo, indexA, unitA, unitB })
  57. })
  58. })
  59. })
  60. })
  61. this.edgeCount = count
  62. this.edges = edges
  63. this.edgeKeyIndex = edgeKeyIndex
  64. this.vertexKeyIndex = elementKeyIndex
  65. }
  66. }
  67. namespace InterUnitGraph {
  68. export class UnitPairEdges<Unit extends UnitBase, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
  69. hasEdges(indexA: VertexIndex) {
  70. return this.edgeMap.has(indexA);
  71. }
  72. getEdges(indexA: VertexIndex): ReadonlyArray<EdgeInfo<VertexIndex, EdgeProps>> {
  73. if (!this.edgeMap.has(indexA)) return emptyArray;
  74. return this.edgeMap.get(indexA)!;
  75. }
  76. get areUnitsOrdered() {
  77. return this.unitA.id < this.unitB.id;
  78. }
  79. constructor(public unitA: Unit, public unitB: Unit,
  80. public edgeCount: number, public connectedIndices: ReadonlyArray<VertexIndex>,
  81. private edgeMap: Map<number, EdgeInfo<VertexIndex, EdgeProps>[]>) {
  82. }
  83. }
  84. export type UnitBase = { id: number }
  85. export type EdgePropsBase = { [name: string]: any }
  86. export interface EdgeInfo<VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
  87. /** indexInto */
  88. readonly indexB: VertexIndex,
  89. readonly props: EdgeProps
  90. }
  91. export interface Edge<Unit extends UnitBase, VertexIndex extends number, EdgeProps extends EdgePropsBase = {}> {
  92. readonly unitA: Unit,
  93. readonly unitB: Unit,
  94. readonly indexA: VertexIndex,
  95. readonly indexB: VertexIndex,
  96. readonly props: EdgeProps
  97. }
  98. export function getEdgeKey<Unit extends UnitBase, VertexIndex extends number>(indexA: VertexIndex, unitA: Unit, indexB: VertexIndex, unitB: Unit) {
  99. return `${indexA}|${unitA.id}|${indexB}|${unitB.id}`
  100. }
  101. export function getVertexKey<Unit extends UnitBase, VertexIndex extends number>(index: VertexIndex, unit: Unit) {
  102. return `${index}|${unit.id}`
  103. }
  104. }
  105. const emptyArray: any[] = [];