// Can only add overlapping pairs. // Sort edge up and add overlapping pairs private void SortMaxEdgeUp(List<Edge> edgeList, int axisIndex, int edgeIndex) { int maxIndex = edgeList.Count - 1; if (edgeIndex == maxIndex) return; var edge = edgeList[edgeIndex]; var itemInfo = edge.Info; int nextEdgeIndex = edgeIndex + 1; var nextEdge = edgeList[nextEdgeIndex]; while (edge.Position >= nextEdge.Position) { var nextItemInfo = nextEdge.Info; if (nextEdge.IsMax == false) { // New overlapping pair! if (_broadPhase != null || EnableSelfOverlaps) { if (AreOverlapping(itemInfo, nextItemInfo, axisIndex)) { var overlap = new Pair<T>(itemInfo.Item, nextItemInfo.Item); if (Filter == null || Filter.Filter(overlap)) { if (_broadPhase != null) _broadPhase.Add(overlap); if (EnableSelfOverlaps) SelfOverlaps.Add(overlap); } } } nextItemInfo.MinEdgeIndices[axisIndex] = edgeIndex; // Min edge was swapped down. } else { nextItemInfo.MaxEdgeIndices[axisIndex] = edgeIndex; // Max edge was swapped down. } itemInfo.MaxEdgeIndices[axisIndex] = nextEdgeIndex; // Max edge was swapped up. // Swap edges in edge list. edgeList[edgeIndex] = nextEdge; edgeList[nextEdgeIndex] = edge; edgeIndex++; if (edgeIndex == maxIndex) return; nextEdgeIndex++; nextEdge = edgeList[nextEdgeIndex]; } }
// Can only add overlapping pairs. // Sort edge down and add overlapping pairs. private void SortMinEdgeDown(List<Edge> edgeList, int axisIndex, int edgeIndex) { if (edgeIndex == 0) return; var edge = edgeList[edgeIndex]; var itemInfo = edge.Info; int previousEdgeIndex = edgeIndex - 1; Edge previousEdge = edgeList[previousEdgeIndex]; while (edge.Position <= previousEdge.Position) { var previousItemInfo = previousEdge.Info; if (previousEdge.IsMax) { // New overlapping pair! if (_broadPhase != null || EnableSelfOverlaps) { if (AreOverlapping(itemInfo, previousItemInfo, axisIndex)) { var overlap = new Pair<T>(itemInfo.Item, previousItemInfo.Item); if (Filter == null || Filter.Filter(overlap)) { if (_broadPhase != null) _broadPhase.Add(overlap); if (EnableSelfOverlaps) SelfOverlaps.Add(overlap); } } } previousItemInfo.MaxEdgeIndices[axisIndex] = edgeIndex; // Max edge was swapped up. } else { previousItemInfo.MinEdgeIndices[axisIndex] = edgeIndex; // Min edge was swapped up. } itemInfo.MinEdgeIndices[axisIndex] = previousEdgeIndex; // Min edge was swapped down. // Swap edges in edge list. edgeList[edgeIndex] = previousEdge; edgeList[previousEdgeIndex] = edge; edgeIndex--; if (edgeIndex == 0) return; previousEdgeIndex--; previousEdge = edgeList[previousEdgeIndex]; } }
/// <inheritdoc/> internal override void OnUpdate(bool forceRebuild, HashSet <T> addedItems, HashSet <T> removedItems, HashSet <T> invalidItems) { if (EnableSelfOverlaps) { // Need to find all self-overlaps. SelfOverlaps.Clear(); // Test all items against all items. HashSet <T> .Enumerator outerEnumerator = Items.GetEnumerator(); while (outerEnumerator.MoveNext()) { T item = outerEnumerator.Current; Aabb aabb = GetAabbForItem(item); // Duplicate struct enumerator at current position. HashSet <T> .Enumerator innerEnumerator = outerEnumerator; while (innerEnumerator.MoveNext()) { T otherItem = innerEnumerator.Current; Aabb otherAabb = GetAabbForItem(otherItem); Pair <T> overlap = new Pair <T>(item, otherItem); if (Filter == null || Filter.Filter(overlap)) { if (GeometryHelper.HaveContact(aabb, otherAabb)) { SelfOverlaps.Add(overlap); } } } } // If Items is a IList<T>, which has an indexer, we can use the following code. //for (int i = 0; i < Items.Count; i++) //{ // var itemI = Items[i]; // var aabbI = GetAabbForItem(itemI); // for (int j = i + 1; j < Items.Count; j++) // { // var itemJ = Items[j]; // var aabbJ = GetAabbForItem(itemJ); // var overlap = new Pair<T>(itemI, itemJ); // if (Filter == null || Filter.Filter(overlap)) // if (GeometryHelper.HaveContact(aabbI, aabbJ)) // SelfOverlaps.Add(overlap); // } //} } }
/// <summary> /// Updates the self-overlaps. /// </summary> private void UpdateSelfOverlaps() { if (EnableSelfOverlaps) { // Recompute all self-overlaps by making a tree vs. tree test. SelfOverlaps.Clear(); if (_root != null) { // Important: Do not call GetOverlaps(this) because this would lead to recursive // Update() calls! foreach (var overlap in GetOverlapsImpl(this)) { Debug.Assert(FilterSelfOverlap(overlap), "Filtering should have been applied."); SelfOverlaps.Add(overlap); } } } }
private void UpdateSelfOverlaps() { if (EnableSelfOverlaps) { // Update self-overlaps. SelfOverlaps.Clear(); // ----- Compute self-overlaps using tree vs. tree test. if (_root == null) { return; } // Important: Do not call GetOverlaps(this) because this would lead to recursive // Update() calls! foreach (var overlap in GetOverlapsImpl(this)) { Debug.Assert(FilterSelfOverlap(overlap), "Filtering should have been applied."); SelfOverlaps.Add(overlap); } // ----- Compute self-overlaps using leaf vs. tree test. //if (_root != null) //{ // foreach (var leave in _leaves) // { // foreach (var touchedItem in GetOverlaps(leave.Aabb)) // { // var overlap = new Pair<T>(leave.Item, touchedItem); // if (FilterSelfOverlap(overlap)) // SelfOverlaps.Add(overlap); // } // } //} } }
private void UpdateSelfOverlaps(HashSet <T> addedItems, HashSet <T> removedItems, HashSet <T> invalidItems, List <Node> invalidNodes) { if (!EnableSelfOverlaps) { return; } // If the entire partition or a substantial amount of nodes is invalid use a tree vs. tree // checks. (Faster than leaf vs. tree checks. However, we need to determine the exact // threshold at which tree vs. tree is cheaper. The current threshold of Count / 2 is just // a guess.) if (invalidItems == null || addedItems.Count + invalidItems.Count > Count / 2) { // Recompute all self-overlaps by making a tree vs. tree test. SelfOverlaps.Clear(); if (_root != null) { // Important: Do not call GetOverlaps(this) because this would lead to recursive // Update() calls! // Note: Filtering is applied in GetOverlapsImpl(this). foreach (var overlap in GetOverlapsImpl(this)) { SelfOverlaps.Add(overlap); } } } else { // Merge invalid and removed items into single set. // Store result in invalidItems. if (invalidItems.Count > 0 && removedItems.Count > 0) { // Merge smaller set into larger set. if (invalidItems.Count < removedItems.Count) { MathHelper.Swap(ref invalidItems, ref removedItems); } foreach (var item in removedItems) { invalidItems.Add(item); } } else if (removedItems.Count > 0) { invalidItems = removedItems; } // Remove invalid entries from self-overlaps. if (invalidItems.Count > 0) { var invalidOverlaps = DigitalRune.ResourcePools <Pair <T> > .Lists.Obtain(); foreach (var overlap in SelfOverlaps) { if (invalidItems.Contains(overlap.First) || invalidItems.Contains(overlap.Second)) { invalidOverlaps.Add(overlap); } } foreach (var overlap in invalidOverlaps) { SelfOverlaps.Remove(overlap); } DigitalRune.ResourcePools <Pair <T> > .Lists.Recycle(invalidOverlaps); } // Compute new overlaps for all nodes that were updated in this frame. if (invalidNodes != null) { foreach (var node in invalidNodes) { foreach (var touchedItem in GetOverlapsImpl(node)) { var overlap = new Pair <T>(node.Item, touchedItem); if (Filter == null || Filter.Filter(overlap)) { SelfOverlaps.Add(overlap); } } } } } }
private void AddSelfOverlap(Pair <T> overlap) { Debug.Assert(FilterSelfOverlap(overlap), "Filtering should have been applied."); SelfOverlaps.Add(overlap); }