/// <summary> /// Gets a vertex from the path tree. /// </summary> public override void GetPathTree(PathTree tree, uint pointer, out uint vertex, out float weight, out uint previous) { uint data1; tree.Get(pointer, out vertex, out data1, out previous); weight = data1 / 10.0f; }
/// <summary> /// Gets the visit at the given location. /// </summary> /// <param name="tree">The tree.</param> /// <param name="pointer">The pointer.</param> /// <returns>The visit.</returns> public static (VertexId vertex, uint edge, uint previousPointer) GetVisit(this PathTree tree, uint pointer) { tree.Get(pointer, out var data0, out var data1, out var data2, out var data3); return(new VertexId() { TileId = data0, LocalId = data1 }, data2, data3); }
/// <summary> /// Gets a settled vertex weight. /// </summary> public static WeightAndDir <float> GetSettledVertexWeight(this PathTree tree, uint pointer) { uint data0, data1, data2; tree.Get(pointer, out data0, out data1, out data2); return(new WeightAndDir <float>() { Weight = data1 / WeightFactor, Direction = new Dir() { _val = (byte)(data2 & 3) } }); }
/// <summary> /// Gets a settled vertex. /// </summary> public static void GetSettledVertex(this PathTree tree, uint pointer, out uint vertex, out WeightAndDir <float> weightAndDir, out uint hops) { uint data0, data1, data2; tree.Get(pointer, out data0, out data1, out data2); vertex = data0; weightAndDir = new WeightAndDir <float>() { Weight = data1 / WeightFactor, Direction = new Dir() { _val = (byte)(data2 & 3) } }; hops = data2 / 4; }
/// <summary> /// Finds loops and merges them together. /// </summary> /// <param name="maxSettles">The maximum labels to settle.</param> /// <param name="updateLabel">A callback to update label.</param> internal void FindLoops(uint maxSettles, IslandLabels islandLabels, Action <uint, uint> updateLabel) { // TODO: it's probably better to call reduce here when too much has changed. var pathTree = new PathTree(); var enumerator = _graph.GetEdgeEnumerator(); var settled = new HashSet <uint>(); var queue = new Queue <uint>(); var loop = new HashSet <uint>(); // keeps all with a path back to label, initially only label. uint label = 0; while (label < _graph.VertexCount) { if (!enumerator.MoveTo(label)) { label++; continue; } if (islandLabels[label] != label) { label++; continue; } queue.Clear(); pathTree.Clear(); settled.Clear(); loop.Add(label); queue.Enqueue(pathTree.Add(label, uint.MaxValue)); while (queue.Count > 0 && settled.Count < maxSettles) { var pointer = queue.Dequeue(); pathTree.Get(pointer, out var current, out var previous); if (settled.Contains(current)) { continue; } settled.Add(current); if (!enumerator.MoveTo(current)) { continue; } while (enumerator.MoveNext()) { var n = enumerator.Neighbour; n = islandLabels[n]; if (loop.Contains(n)) { // yay, a loop! loop.Add(current); while (previous != uint.MaxValue) { pathTree.Get(previous, out current, out previous); loop.Add(current); } } if (settled.Contains(n)) { continue; } queue.Enqueue(pathTree.Add(n, pointer)); } } if (loop.Count > 0) { this.Merge(loop, updateLabel); } loop.Clear(); // move to the next label. label++; } }