Aetheria/Assets/Plugins/MSAGL/Layout/Layered/Ordering/AdjacentSwaps.cs
Reinier Vens dbc522a224 Weapos Rejiggered
Modified weapon scripts to eliminate specialized projectile behavior - allows charged weapons to have projectiles and modify weapon stats when charged
Added machine gun weapon & VFX
Moved third party code to Plugins folder to improve compile times
2021-01-31 03:52:32 +00:00

568 lines
No EOL
20 KiB
C#

using System;
using System.Collections.Generic;
namespace Microsoft.Msagl.Layout.Layered {
/// <summary>
/// Following "A technique for Drawing Directed Graphs" of Gansner, Koutsofios, North and Vo
/// Works on the layered graph.
/// For explanations of the algorithm here see https://www.researchgate.net/profile/Lev_Nachmanson/publication/30509007_Drawing_graphs_with_GLEE/links/54b6b2930cf2e68eb27edf71/Drawing-graphs-with-GLEE.pdf
///
/// </summary>
internal partial class Ordering {
/// <summary>
/// for each vertex v let P[v] be the array of predeccessors of v
/// </summary>
int[][] predecessors;
/// <summary>
/// The array contains a dictionary per vertex
/// The value POrder[v][u] gives the offset of u in the array P[v]
/// </summary>
Dictionary<int, int>[] pOrder;
/// <summary>
/// for each vertex v let S[v] be the array of successors of v
/// </summary>
int[][] successors;
/// <summary>
/// The array contains a dictionary per vertex
/// The value SOrder[v][u] gives the offset of u in the array S[v]
/// </summary>
Dictionary<int, int>[] sOrder;
Dictionary<int, int>[] inCrossingCount;
/// <summary>
/// Gets or sets the number of of passes over all layers to rung adjacent exchanges, where every pass goes '
/// all way up to the top layer and down to the lowest layer
/// </summary>
const int MaxNumberOfAdjacentExchanges = 50;
Dictionary<int, int>[] outCrossingCount;
bool HeadOfTheCoin() {
return random.Next(2) == 0;
}
void AdjacentExchangeWithBalancingVirtOrigNodes() {
InitArrays();
int count = 0;
bool progress = true;
while (progress && count++ < MaxNumberOfAdjacentExchanges) {
progress = false;
for (int i = 0; i < layers.Length; i++)
progress = AdjExchangeLayerWithBalance(i) || progress;
for (int i = layers.Length - 2; i >= 0; i--)
progress = AdjExchangeLayerWithBalance(i) || progress;
}
}
void AdjacentExchange() {
InitArrays();
int count = 0;
bool progress = true;
while (progress && count++ < MaxNumberOfAdjacentExchanges) {
progress = false;
for (int i = 0; i < layers.Length; i++)
progress = AdjExchangeLayer(i) || progress;
for (int i = layers.Length - 2; i >= 0; i--)
progress = AdjExchangeLayer(i) || progress;
}
}
void AllocArrays() {
int n = properLayeredGraph.NodeCount;
predecessors = new int[n][];
successors = new int[n][];
pOrder = new Dictionary<int, int>[n];
sOrder = new Dictionary<int, int>[n];
if (hasCrossWeights) {
outCrossingCount = new Dictionary<int, int>[n];
inCrossingCount = new Dictionary<int, int>[n];
}
for (int i = 0; i < n; i++) {
int count = properLayeredGraph.InEdgesCount(i);
predecessors[i] = new int[count];
if (hasCrossWeights) {
Dictionary<int, int> inCounts = inCrossingCount[i] = new Dictionary<int, int>(count);
foreach (LayerEdge le in properLayeredGraph.InEdges(i))
inCounts[le.Source] = le.CrossingWeight;
}
pOrder[i] = new Dictionary<int, int>(count);
count = properLayeredGraph.OutEdgesCount(i);
successors[i] = new int[count];
sOrder[i] = new Dictionary<int, int>(count);
if (hasCrossWeights) {
Dictionary<int, int> outCounts = outCrossingCount[i] = new Dictionary<int, int>(count);
foreach (LayerEdge le in properLayeredGraph.OutEdges(i))
outCounts[le.Target] = le.CrossingWeight;
}
}
}
/// <summary>
/// Is called just after median layer swap is done
/// </summary>
void InitArrays() {
if (successors == null)
AllocArrays();
for (int i = 0; i < properLayeredGraph.NodeCount; i++) {
pOrder[i].Clear();
sOrder[i].Clear();
}
foreach (int[] t in layers)
InitPsArraysForLayer(t);
}
/// <summary>
/// calculates the number of intersections between edges adjacent to u and v
/// </summary>
/// <param name="u">a vertex</param>
/// <param name="v">a vertex</param>
/// <param name="cuv">the result when u is to the left of v</param>
/// <param name="cvu">the result when v is to the left of u</param>
void CalcPair(int u, int v, out int cuv, out int cvu) {
int[] su = successors[u], sv = successors[v], pu = predecessors[u], pv = predecessors[v];
if (!hasCrossWeights) {
cuv = CountOnArrays(su, sv) +
CountOnArrays(pu, pv);
cvu = CountOnArrays(sv, su) +
CountOnArrays(pv, pu);
} else {
Dictionary<int, int> uOutCrossCounts = outCrossingCount[u];
Dictionary<int, int> vOutCrossCounts = outCrossingCount[v];
Dictionary<int, int> uInCrossCounts = inCrossingCount[u];
Dictionary<int, int> vInCrossCounts = inCrossingCount[v];
cuv = CountOnArrays(su, sv, uOutCrossCounts, vOutCrossCounts) +
CountOnArrays(pu, pv, uInCrossCounts, vInCrossCounts);
cvu = CountOnArrays(sv, su, vOutCrossCounts, uOutCrossCounts) +
CountOnArrays(pv, pu, vInCrossCounts, uInCrossCounts);
}
}
/// <summary>
/// Sweep layer from left to right and fill S,P arrays as we go.
/// The arrays P and S will be sorted according to X. Note that we will not keep them sorted
/// as we doing adjacent swaps. Initial sorting only needed to calculate initial clr,crl values.
/// </summary>
/// <param name="layer"></param>
void InitPsArraysForLayer(int[] layer) {
this.ProgressStep();
foreach (int l in layer) {
foreach (int p in properLayeredGraph.Pred(l)) {
Dictionary<int, int> so = sOrder[p];
int sHasNow = so.Count;
successors[p][sHasNow] = l; //l takes the first available slot in S[p]
so[l] = sHasNow;
}
foreach (int s in properLayeredGraph.Succ(l)) {
Dictionary<int, int> po = pOrder[s];
int pHasNow = po.Count;
predecessors[s][pHasNow] = l; //l take the first available slot in P[s]
po[l] = pHasNow;
}
}
}
int CountOnArrays(int[] unbs, int[] vnbs) {
int ret = 0;
int vl = vnbs.Length - 1;
int j = -1; //the right most position of vnbs to the left from the current u neighbor
int vnbsSeenAlready = 0;
foreach (int uNeighbor in unbs) {
int xu = X[uNeighbor];
for (; j < vl && X[vnbs[j + 1]] < xu; j++)
vnbsSeenAlready++;
ret += vnbsSeenAlready;
}
return ret;
}
/// <summary>
/// every inversion between unbs and vnbs gives an intersecton
/// </summary>
/// <param name="unbs">neighbors of u but only from one layer</param>
/// <param name="vnbs">neighbors of v from the same layers</param>
/// <returns>number of intersections when u is to the left of v</returns>
/// <param name="uCrossingCounts"></param>
/// <param name="vCrossingCount"></param>
int CountOnArrays(int[] unbs, int[] vnbs, Dictionary<int, int> uCrossingCounts,
Dictionary<int, int> vCrossingCount) {
int ret = 0;
int vl = vnbs.Length - 1;
int j = -1; //the right most position of vnbs to the left from the current u neighbor
int vCrossingNumberSeenAlready = 0;
foreach (int uNeib in unbs) {
int xu = X[uNeib];
int vnb;
for (; j < vl && X[vnb = vnbs[j + 1]] < xu; j++)
vCrossingNumberSeenAlready += vCrossingCount[vnb];
ret += vCrossingNumberSeenAlready*uCrossingCounts[uNeib];
}
return ret;
}
bool AdjExchangeLayer(int i) {
this.ProgressStep();
int[] layer = layers[i];
bool gain = ExchangeWithGainWithNoDisturbance(layer);
if (gain)
return true;
DisturbLayer(layer);
return ExchangeWithGainWithNoDisturbance(layer);
}
bool AdjExchangeLayerWithBalance(int i) {
this.ProgressStep();
int[] layer = layers[i];
bool gain = ExchangeWithGainWithNoDisturbanceWithBalance(layer);
if (gain)
return true;
DisturbLayerWithBalance(layer);
return ExchangeWithGainWithNoDisturbanceWithBalance(layer);
}
//in this routine u and v are adjacent, and u is to the left of v before the swap
void Swap(int u, int v) {
int left = X[u];
int right = X[v];
int ln = layering[u]; //layer number
int[] layer = layers[ln];
layer[left] = v;
layer[right] = u;
X[u] = right;
X[v] = left;
//update sorted arrays POrders and SOrders
//an array should be updated only in case it contains both u and v.
// More than that, v has to follow u in an the array.
UpdateSsContainingUv(u, v);
UpdatePsContainingUv(u, v);
}
void UpdatePsContainingUv(int u, int v) {
if (successors[u].Length <= successors[v].Length)
foreach (int a in successors[u]) {
Dictionary<int, int> porder = pOrder[a];
//of course porder contains u, let us see if it contains v
if (porder.ContainsKey(v)) {
int vOffset = porder[v];
//swap u and v in the array P[coeff]
int[] p = predecessors[a];
p[vOffset - 1] = v;
p[vOffset] = u;
//update sorder itself
porder[v] = vOffset - 1;
porder[u] = vOffset;
}
}
else
foreach (int a in successors[v]) {
Dictionary<int, int> porder = pOrder[a];
//of course porder contains u, let us see if it contains v
if (porder.ContainsKey(u)) {
int vOffset = porder[v];
//swap u and v in the array P[coeff]
int[] p = predecessors[a];
p[vOffset - 1] = v;
p[vOffset] = u;
//update sorder itself
porder[v] = vOffset - 1;
porder[u] = vOffset;
}
}
}
void UpdateSsContainingUv(int u, int v) {
if (predecessors[u].Length <= predecessors[v].Length)
foreach (int a in predecessors[u]) {
Dictionary<int, int> sorder = sOrder[a];
//of course sorder contains u, let us see if it contains v
if (sorder.ContainsKey(v)) {
int vOffset = sorder[v];
//swap u and v in the array S[coeff]
int[] s = successors[a];
s[vOffset - 1] = v;
s[vOffset] = u;
//update sorder itself
sorder[v] = vOffset - 1;
sorder[u] = vOffset;
}
}
else
foreach (int a in predecessors[v]) {
Dictionary<int, int> sorder = sOrder[a];
//of course sorder contains u, let us see if it contains v
if (sorder.ContainsKey(u)) {
int vOffset = sorder[v];
//swap u and v in the array S[coeff]
int[] s = successors[a];
s[vOffset - 1] = v;
s[vOffset] = u;
//update sorder itself
sorder[v] = vOffset - 1;
sorder[u] = vOffset;
}
}
}
void DisturbLayer(int[] layer) {
for (int i = 0; i < layer.Length - 1; i++)
AdjacentSwapToTheRight(layer, i);
}
void DisturbLayerWithBalance(int[] layer) {
for (int i = 0; i < layer.Length - 1; i++)
AdjacentSwapToTheRightWithBalance(layer, i);
}
bool ExchangeWithGainWithNoDisturbance(int[] layer) {
bool wasGain = false;
bool gain;
do {
gain = ExchangeWithGain(layer);
wasGain = wasGain || gain;
} while (gain);
return wasGain;
}
bool ExchangeWithGainWithNoDisturbanceWithBalance(int[] layer) {
bool wasGain = false;
bool gain;
do {
gain = ExchangeWithGainWithBalance(layer);
wasGain = wasGain || gain;
} while (gain);
return wasGain;
}
bool ExchangeWithGain(int[] layer) {
//find a first pair giving some gain
for (int i = 0; i < layer.Length - 1; i++)
if (SwapWithGain(layer[i], layer[i + 1])) {
SwapToTheLeft(layer, i);
SwapToTheRight(layer, i + 1);
return true;
}
return false;
}
bool ExchangeWithGainWithBalance(int[] layer) {
//find a first pair giving some gain
for (int i = 0; i < layer.Length - 1; i++)
if (SwapWithGainWithBalance(layer[i], layer[i + 1])) {
SwapToTheLeftWithBalance(layer, i);
SwapToTheRightWithBalance(layer, i + 1);
return true;
}
return false;
}
void SwapToTheLeft(int[] layer, int i) {
for (int j = i - 1; j >= 0; j--)
AdjacentSwapToTheRight(layer, j);
}
void SwapToTheRight(int[] layer, int i) {
for (int j = i; j < layer.Length - 1; j++)
AdjacentSwapToTheRight(layer, j);
}
void SwapToTheLeftWithBalance(int[] layer, int i) {
for (int j = i - 1; j >= 0; j--)
AdjacentSwapToTheRightWithBalance(layer, j);
}
void SwapToTheRightWithBalance(int[] layer, int i) {
for (int j = i; j < layer.Length - 1; j++)
AdjacentSwapToTheRightWithBalance(layer, j);
}
/// <summary>
/// swaps i-th element with i+1
/// </summary>
/// <param name="layer">the layer to work on</param>
/// <param name="i">the position to start</param>
void AdjacentSwapToTheRight(int[] layer, int i) {
int u = layer[i], v = layer[i + 1];
int gain = SwapGain(u, v);
if (gain > 0 || (gain == 0 && HeadOfTheCoin()))
Swap(u, v);
}
void AdjacentSwapToTheRightWithBalance(int[] layer, int i) {
int u = layer[i], v = layer[i + 1];
int gain = SwapGainWithBalance(u, v);
if (gain > 0 || (gain == 0 && HeadOfTheCoin()))
Swap(u, v);
}
int SwapGain(int u, int v) {
int cuv;
int cvu;
CalcPair(u, v, out cuv, out cvu);
return cuv - cvu;
}
int SwapGainWithBalance(int u, int v) {
int cuv;
int cvu;
CalcPair(u, v, out cuv, out cvu);
int gain = cuv - cvu;
if (gain != 0 && UvAreOfSameKind(u, v))
return gain;
//maybe we gain something in the group sizes
return SwapGroupGain(u, v);
}
bool UvAreOfSameKind(int u, int v) {
return u < startOfVirtNodes && v < startOfVirtNodes || u >= startOfVirtNodes && v >= startOfVirtNodes;
}
int SwapGroupGain(int u, int v) {
int layerIndex = layerArrays.Y[u];
int[] layer = layers[layerIndex];
if (NeighborsForbidTheSwap(u, v))
return -1;
int uPosition = X[u];
bool uIsSeparator;
if (IsOriginal(u))
uIsSeparator = optimalOriginalGroupSize[layerIndex] == 1;
else
uIsSeparator = optimalVirtualGroupSize[layerIndex] == 1;
int delta = CalcDeltaBetweenGroupsToTheLeftAndToTheRightOfTheSeparator(layer,
uIsSeparator
? uPosition
: uPosition + 1,
uIsSeparator ? u : v);
if (uIsSeparator) {
if (delta < -1)
return 1;
if (delta == -1)
return 0;
return -1;
}
if (delta > 1)
return 1;
if (delta == 1)
return 0;
return -1;
}
bool NeighborsForbidTheSwap(int u, int v) {
return UpperNeighborsForbidTheSwap(u, v) || LowerNeighborsForbidTheSwap(u, v);
}
bool LowerNeighborsForbidTheSwap(int u, int v) {
int uCount, vCount;
if (((uCount = properLayeredGraph.OutEdgesCount(u)) == 0) ||
((vCount = properLayeredGraph.OutEdgesCount(v)) == 0))
return false;
return X[successors[u][uCount >> 1]] < X[successors[v][vCount >> 1]];
}
bool UpperNeighborsForbidTheSwap(int u, int v) {
int uCount = properLayeredGraph.InEdgesCount(u);
int vCount = properLayeredGraph.InEdgesCount(v);
if (uCount == 0 || vCount == 0)
return false;
return X[predecessors[u][uCount >> 1]] < X[predecessors[v][vCount >> 1]];
}
int CalcDeltaBetweenGroupsToTheLeftAndToTheRightOfTheSeparator(int[] layer, int separatorPosition, int separator) {
Func<int, bool> kind = GetKindDelegate(separator);
int leftGroupSize = 0;
for (int i = separatorPosition - 1; i >= 0 && !kind(layer[i]); i--)
leftGroupSize++;
int rightGroupSize = 0;
for (int i = separatorPosition + 1; i < layer.Length && !kind(layer[i]); i++)
rightGroupSize++;
return leftGroupSize - rightGroupSize;
}
bool IsOriginal(int v) {
return v < startOfVirtNodes;
}
bool IsVirtual(int v) {
return v >= startOfVirtNodes;
}
Func<int, bool> GetKindDelegate(int v) {
Func<int, bool> kind = IsVirtual(v) ? IsVirtual : new Func<int, bool>(IsOriginal);
return kind;
}
///// <summary>
///// swaps two vertices only if reduces the number of intersections
///// </summary>
///// <param name="layer">the layer to work on</param>
///// <param name="u">left vertex</param>
///// <param name="v">right vertex</param>
///// <returns></returns>
bool SwapWithGain(int u, int v) {
int gain = SwapGain(u, v);
if (gain > 0) {
Swap(u, v);
return true;
}
return false;
}
bool SwapWithGainWithBalance(int u, int v) {
int gain = SwapGainWithBalance(u, v);
if (gain > 0) {
Swap(u, v);
return true;
}
return false;
}
}
}