private BaseProjectionBuffer PickIndependentBuffer() { // pick a buffer for which all source buffers have finished participating in the master edit. // source buffer could be stable because // 1. it is in the source closure of the master buffer -- all those edits are done by now // 2. it isn't in the target closure of the master buffer // 3. it has already been picked by this method // for the moment, we are ignoring #2, and such buffers won't get picked (resulting in an exception). foreach (BaseProjectionBuffer projectionBuffer in this.pendingIndependentBuffers) { bool ok = true; foreach (ITextBuffer sourceBuffer in projectionBuffer.SourceBuffers) { if (!IsStableDuringIndependentPhase((BaseBuffer)sourceBuffer)) { ok = false; break; } } if (ok) { GraphEntry gg = this.graph[(BaseBuffer)projectionBuffer]; gg.Dependent = true; // indicate has been chosen this.pendingIndependentBuffers.Remove(projectionBuffer); return(projectionBuffer); } } throw new InvalidOperationException("Couldn't pick an independent buffer"); }
private void UpdateGraphList() { if (m_graphsInProject == null) { return; } var guids = AssetDatabase.FindAssets(Model.Settings.GRAPH_SEARCH_CONDITION); var newList = new List <GraphEntry>(guids.Length); foreach (var guid in guids) { var e = m_graphsInProject.Find(v => v.Guid == guid); if (e == null) { e = new GraphEntry(guid); } else { e.Refresh(); } newList.Add(e); } m_graphsInProject = newList; }
private void ProcessBestEntry(GraphEntry bestEntry) { // First we should remove the entry from the candidate array Assert.IsTrue(_sortedCandidateGraphEntries [0] == bestEntry); _sortedCandidateGraphEntries.RemoveAt(0); GraphElement bestElement = bestEntry.graphElement; #if !REQUIRE_STRUCT Assert.IsTrue(bestElement != null); #endif // Now we should add/update all the connected entries. if (bestEntry.connectedElements != null) { foreach (GraphElement currConnectedElement in bestEntry.connectedElements) { float connectionCost = _graph.getActualCostForMovementBetweenElementsFunc(bestElement, currConnectedElement); float totalCostToConnection = bestEntry.bestCostToHere + connectionCost; GraphEntry connectedEntry = GetEntryForElement(currConnectedElement); if (connectedEntry == _startEntry) { // This is the start entry so just ignore it as the best route never returns to the start point! } else if (connectedEntry == _targetEntry) { // We've reached the target entry, add it as a sorted candidate, we're only finished if this route becomes the best possible. if (connectedEntry.bestCostVia == null || totalCostToConnection < connectedEntry.bestCostToHere) { connectedEntry.SetBestCost(bestEntry, totalCostToConnection); AddSortedCandidate(connectedEntry); } } else if (connectedEntry != null && connectedEntry.bestCostVia != null) { // We've already visited this entry so see if this is the optimum route. if (totalCostToConnection < connectedEntry.bestCostToHere) { // This route is shorter than the one we've previously found so replace it. RemoveSortedCandidate(connectedEntry); connectedEntry.SetBestCost(bestEntry, totalCostToConnection); AddSortedCandidate(connectedEntry); } } else { // This is the first time we've seen this entry so just add it Assert.IsTrue(connectedEntry == null || connectedEntry.bestCostVia == null); if (connectedEntry == null) { connectedEntry = CreateGraphEntryFor(currConnectedElement); } connectedEntry.SetBestCost(bestEntry, totalCostToConnection); AddSortedCandidate(connectedEntry); } } } }
public void SetBestCost(GraphEntry viaEntry, float totalCostToHere) { Assert.IsTrue(totalCostToHere < this.bestCostToHere || bestCostVia == null); Assert.IsTrue(totalCostToHere >= 0.0f); Assert.IsTrue(viaEntry != null); Assert.IsTrue(totalCostToHere >= viaEntry.bestCostToHere); // We can't have a smaller cost than our via entry. this._bestCostToHere = totalCostToHere; this._bestCostVia = viaEntry; }
private void RemoveSortedCandidate(GraphEntry candidateEntry) { Assert.IsTrue(candidateEntry != null); CandidateComparer comparer = new CandidateComparer(); int findIndex = _sortedCandidateGraphEntries.BinarySearch(candidateEntry, comparer); if (findIndex >= 0) { // Find the lower bound... int lowerBound = findIndex; while (lowerBound > 0) { if (comparer.Compare(_sortedCandidateGraphEntries[lowerBound - 1], _sortedCandidateGraphEntries[findIndex]) == 0) { --lowerBound; } else { break; } } // Find the upper bound... int upperBound = findIndex; while (upperBound < (_sortedCandidateGraphEntries.Count - 1)) { if (comparer.Compare(_sortedCandidateGraphEntries[upperBound + 1], _sortedCandidateGraphEntries[findIndex]) == 0) { ++upperBound; } else { break; } } // Loop over all possible candidates until we find the one we're looking for. for (int currTestIndex = lowerBound; currTestIndex <= upperBound; ++currTestIndex) { Assert.IsTrue(comparer.Compare(_sortedCandidateGraphEntries[currTestIndex], _sortedCandidateGraphEntries[findIndex]) == 0); if (_sortedCandidateGraphEntries[findIndex] == candidateEntry) { _sortedCandidateGraphEntries.RemoveAt(findIndex); break; } } } }
private void MarkMasterClosure(BaseBuffer buffer) { GraphEntry g = this.graph[buffer]; if (!g.Dependent) { g.Dependent = true; IProjectionBufferBase projectionBuffer = buffer as IProjectionBufferBase; if (projectionBuffer != null) { foreach (BaseBuffer source in projectionBuffer.SourceBuffers) { MarkMasterClosure(source); } } } }
private bool InTargetClosureOfBuffer(BaseBuffer candidateBuffer, BaseBuffer governingBuffer) { GraphEntry g = this.graph[governingBuffer]; foreach (var target in g.Targets) { if (target == candidateBuffer) { return(true); } if (InTargetClosureOfBuffer(candidateBuffer, (BaseBuffer)target)) { return(true); } } return(false); }
private bool InvulnerableToFutureEdits(GraphEntry graphEntry) { foreach (IProjectionBufferBase target in graphEntry.Targets) { BaseBuffer baseTarget = (BaseBuffer)target; GraphEntry targetEntry = this.graph[baseTarget]; if (targetEntry.EditComplete) { continue; } if (InvulnerableToFutureEdits(targetEntry) && !this.buffer2EditMap.ContainsKey(baseTarget)) { targetEntry.EditComplete = true; continue; } return(false); } return(true); }
private void AddSortedCandidate(GraphEntry newCandidateEntry) { // Only actually add if if it is possible that it will produce a better solution than our existing best solution, and that it's better than the worst cost we're interested in. float currBestSolutionCost = _targetEntry.currentBestPossibleTotalCost; if (newCandidateEntry.currentBestPossibleTotalCost <= _maxAcceptableRouteLength && (_targetEntry.bestCostVia == null || newCandidateEntry.currentBestPossibleTotalCost < currBestSolutionCost)) { int findIndex = _sortedCandidateGraphEntries.BinarySearch(newCandidateEntry, _candidateComparer); if (findIndex < 0) { // We didn't find it so insert it at the bitwise compliment of findIndex (see https://msdn.microsoft.com/en-us/library/w4e7fxsh(v=vs.110).aspx) _sortedCandidateGraphEntries.Insert(~findIndex, newCandidateEntry); } else { _sortedCandidateGraphEntries.Insert(findIndex, newCandidateEntry); } } }
private GraphEntry CreateGraphEntryFor(GraphElement graphElement) { Assert.IsTrue(!_graphEntries.ContainsKey(graphElement)); // We should only be creating a new element if there isn't one already. // If the _targetEntry hasn't been setup yet then we must be building it now. Pass null (which evaluates to zero estimated cost as we ARE the target). GraphEntry newEntry; if (_graphEntryCache.Count == 0) { newEntry = new GraphEntry(this); } else { newEntry = _graphEntryCache.Last(); _graphEntryCache.RemoveAt(_graphEntryCache.Count - 1); } newEntry.Setup(graphElement); _graphEntries [graphElement] = newEntry; return(newEntry); }
/// <summary> /// Extracts a list of GraphElements representing the shortest route from start to finish. /// Returns null if no such route was found. /// </summary> /// <returns>The solution.</returns> /// <param name="targetElement">Target element.</param> private List <GraphElement> ExtractSolution(GraphElement targetElement, bool allowPartialSolution) { List <GraphElement> solutionList = null; GraphEntry currEntry = GetEntryForElement(targetElement); bool hasCompleteSolution = currEntry != null && currEntry.bestCostVia != null; if (!hasCompleteSolution && allowPartialSolution) { // Get a list of all the entries which we did reach in our search. var viableEntries = _graphEntries.Values.Where(reachedFilterEntry => (reachedFilterEntry.bestCostVia != null || reachedFilterEntry == _startEntry)); if (!(viableEntries.Count() == 0)) { // Filter the list down to the entries which got the closest possible distance away from the target... var orderedViableEntries = viableEntries.OrderBy(distFromSolutionEntry => distFromSolutionEntry.bestPossibleCostToTarget); float bestPossibleRemainingCost = orderedViableEntries.First().bestPossibleCostToTarget; viableEntries = viableEntries.Where(filderRemaininCostEntry => filderRemaininCostEntry.bestPossibleCostToTarget == bestPossibleRemainingCost); Assert.IsFalse(viableEntries.Count() == 0); // Order the remaining viable entries by the total cost and pick the smallest... orderedViableEntries = viableEntries.OrderBy(totalCostOrderEntry => totalCostOrderEntry.currentBestPossibleTotalCost); Assert.IsFalse(orderedViableEntries.Count() == 0); // Set the curr entry to be the best possible end entry... currEntry = orderedViableEntries.First(); } } // Now we know where the path ends, trace the route back to the start entry. if (currEntry != null && (currEntry.bestCostVia != null || currEntry == _startEntry)) { solutionList = new List <GraphElement> (); while (currEntry != null) { solutionList.Add(currEntry.graphElement); currEntry = currEntry.bestCostVia; } solutionList.Reverse(); } return(solutionList); }
private void HandleFrame(LayerSectionFilter filter, DataFrame frame) { string name = GenerateName(filter, frame); GraphEntry startEntry = null; lock (_graphEntries) { if (!_shuttingDown) { if (_graphEntries.ContainsKey(name)) { _graphEntries[name].GetInputAdapter(_direction).Enqueue(frame); } else { LayerSectionDataAdapter clientAdapter = new LayerSectionDataAdapter(this); LayerSectionDataAdapter serverAdapter = new LayerSectionDataAdapter(_linkedNode); if (_direction == LayerSectionGraphDirection.ClientToServer) { LayerSectionDataAdapter temp = clientAdapter; clientAdapter = serverAdapter; serverAdapter = temp; } var clients = filter.Factory.GetNodes <ClientEndpointFactory>(); var servers = filter.Factory.GetNodes <ServerEndpointFactory>(); if ((clients.Length > 0) && (servers.Length > 0)) { MetaDictionary meta = filter.IsolatedGraph ? new MetaDictionary() : Graph.Meta; NetGraph graph = filter.Factory.Create(Graph.Logger, Graph, Graph.GlobalMeta, meta, Graph.ConnectionProperties.AddBag(name)); graph.Name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", Name, name); startEntry = new GraphEntry(filter, clientAdapter, serverAdapter, graph, clients[0].Id, servers[0].Id, ProxyNetworkService.GetLayerBinding(Graph)); startEntry.GetInputAdapter(_direction).Enqueue(frame); _graphEntries[name] = startEntry; } else { throw new ArgumentException(CANAPE.Net.Properties.Resources.LayerSectionNode_InvalidGraph); } } } } // Ensure this is done outside the lock if (startEntry != null) { startEntry.NegotiationThread = new Thread(() => { try { startEntry.Start(); } catch (Exception ex) { Graph.Logger.LogException(ex); lock (_graphEntries) { _graphEntries.Remove(name); startEntry.Dispose(); } } } ); startEntry.NegotiationThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture; startEntry.NegotiationThread.IsBackground = true; startEntry.NegotiationThread.Start(); } }
/// <summary> /// Calculates the shortest route through the graph to the target using the given LazyGraph callbacks. /// </summary> /// <param name="startingElement">Starting element.</param> /// <param name="allowPartialSolution">If true, then the closest to complete solution will be used, even if the solution /// doesn't actually reacth the target position.</param> public IList <GraphElement> Calculate(GraphElement startElement, GraphElement targetElement, bool allowPartialSolution = false, float maxAcceptableRouteLength = float.MaxValue) { #if !REQUIRE_STRUCT Assert.IsTrue(startElement != null); Assert.IsTrue(targetElement != null); #endif Assert.IsTrue(0.0f < maxAcceptableRouteLength); // Special case for if we are starting our search at the target element. if (startElement.Equals(targetElement)) { return(new List <GraphElement> { targetElement }); } Assert.IsTrue(_sortedCandidateGraphEntries != null && _sortedCandidateGraphEntries.Count == 0); // Clear all the cached data if the search has changed... { Assert.IsTrue(_graphEntries != null); bool hasSearchChanged = false; if (_maxAcceptableRouteLength != maxAcceptableRouteLength) { _maxAcceptableRouteLength = maxAcceptableRouteLength; hasSearchChanged = true; } if (_startEntry != null && !startElement.Equals(_startEntry.graphElement)) { hasSearchChanged = true; } // Set the target entry... if (_targetEntry != null && !targetElement.Equals(_targetEntry.graphElement)) { hasSearchChanged = true; } if (hasSearchChanged) { _startEntry = null; _targetEntry = null; _graphEntries.Clear(); } } if (_targetEntry == null) { _targetEntry = CreateGraphEntryFor(targetElement); } Assert.IsTrue(_targetEntry.graphElement.Equals(targetElement)); // Initialise the search graph with the starting element... AddStartGraphEntry(startElement); while (true) { if (_sortedCandidateGraphEntries.Count == 0) { // We're run out of candidates and haven't found the solution. // There is no route across the graph. :-(. break; } else { GraphEntry currTestEntry = GetCurrBestTestEntry(); if (currTestEntry.Equals(targetElement)) { // We have a full best solution to the target. break; } else { ProcessBestEntry(currTestEntry); } } } List <GraphElement> solutionList = ExtractSolution(targetElement, allowPartialSolution); Assert.IsTrue(solutionList == null || startElement.Equals(solutionList[0])); // Reset the working data. _sortedCandidateGraphEntries.Clear(); return(solutionList); }
private void HandleFrame(LayerSectionFilter filter, DataFrame frame) { string name = GenerateName(filter, frame); GraphEntry startEntry = null; lock (_graphEntries) { if (!_shuttingDown) { if (_graphEntries.ContainsKey(name)) { _graphEntries[name].GetInputAdapter(_direction).Enqueue(frame); } else { LayerSectionDataAdapter clientAdapter = new LayerSectionDataAdapter(this); LayerSectionDataAdapter serverAdapter = new LayerSectionDataAdapter(_linkedNode); if (_direction == LayerSectionGraphDirection.ClientToServer) { LayerSectionDataAdapter temp = clientAdapter; clientAdapter = serverAdapter; serverAdapter = temp; } var clients = filter.Factory.GetNodes<ClientEndpointFactory>(); var servers = filter.Factory.GetNodes<ServerEndpointFactory>(); if ((clients.Length > 0) && (servers.Length > 0)) { MetaDictionary meta = filter.IsolatedGraph ? new MetaDictionary() : Graph.Meta; NetGraph graph = filter.Factory.Create(Graph.Logger, Graph, Graph.GlobalMeta, meta, Graph.ConnectionProperties.AddBag(name)); graph.Name = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", Name, name); startEntry = new GraphEntry(filter, clientAdapter, serverAdapter, graph, clients[0].Id, servers[0].Id, ProxyNetworkService.GetLayerBinding(Graph)); startEntry.GetInputAdapter(_direction).Enqueue(frame); _graphEntries[name] = startEntry; } else { throw new ArgumentException(CANAPE.Net.Properties.Resources.LayerSectionNode_InvalidGraph); } } } } // Ensure this is done outside the lock if (startEntry != null) { startEntry.NegotiationThread = new Thread(() => { try { startEntry.Start(); } catch (Exception ex) { Graph.Logger.LogException(ex); lock (_graphEntries) { _graphEntries.Remove(name); startEntry.Dispose(); } } } ); startEntry.NegotiationThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture; startEntry.NegotiationThread.IsBackground = true; startEntry.NegotiationThread.Start(); } }