Aetheria/Assets/Plugins/MSAGL/Miscellaneous/NonOverlappingBoundaries/ProximityQuery.cs

102 lines
4.3 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Msagl.Core.DataStructures;
using Microsoft.Msagl.Core.Geometry;
namespace Microsoft.Msagl.Prototype.NonOverlappingBoundaries {
/// <summary>
/// An IHull is used for proximity queries and should implement the Project method which (similar to IConstraint)
/// should remove overlap between two hulls by moving them as little as possible
/// </summary>
public interface IHull {
/// <summary>
/// Actual or weighted center of the hull
/// </summary>
Point Center { get; }
/// <summary>
///
/// </summary>
/// <param name="delta"></param>
void MoveCenter(Point delta);
/// <summary>
/// Bounding box
/// </summary>
RectangleNode<IHull> RectangleNode { get; }
/// <summary>
/// Remove overlap between this and another IHull by moving them both as little as possible
/// </summary>
/// <param name="other"></param>
/// <returns>amount of displacement</returns>
double Project(IHull other);
}
/// <summary>
/// Uses Lev's HierarchyCalculatorWithRectangularNodes to do overlap queries
/// </summary>
internal class ProximityQuery {
internal ProximityQuery(List<IHull> nodeHulls) {
hierarchy = RectangleNode<IHull>.CreateRectangleNodeOnEnumeration(GetNodeRects(nodeHulls));
}
/// <summary>
/// Find all overlapping pairs.
/// </summary>
/// <returns>List of overlapping pairs</returns>
internal List<Tuple<IHull, IHull>> GetAllIntersections() {
List<Tuple<IHull, IHull>> closePairs = new List<Tuple<IHull, IHull>>();
GetClosePairs(hierarchy, hierarchy, closePairs);
return closePairs;
}
private RectangleNode<IHull> hierarchy;
/// <summary>
/// Search in the hierarchy for rectangles that intersect with leafNode.
/// </summary>
/// <param name="leafNode"></param>
/// <param name="intersecting"></param>
/// <param name="internalNode"></param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void GetIntersecting(RectangleNode<IHull> leafNode, RectangleNode<IHull> internalNode, List<IHull> intersecting) {
Debug.Assert(leafNode.UserData != null);
if (!leafNode.Rectangle.Intersects(internalNode.Rectangle))
return;
if (internalNode.UserData != null) {
if (leafNode.UserData != internalNode.UserData) {
intersecting.Add(internalNode.UserData);
}
} else {
GetIntersecting(leafNode, internalNode.Left, intersecting);
GetIntersecting(leafNode, internalNode.Right, intersecting);
}
}
private void GetClosePairs(RectangleNode<IHull> a, RectangleNode<IHull> b, List<Tuple<IHull, IHull>> closePairs) {
if (!a.Rectangle.Intersects(b.Rectangle))
return;
if (a.UserData != null && b.UserData != null) {
if (a.UserData != b.UserData) {
Point ap = a.UserData.Center;
Point bp = b.UserData.Center;
if (ap.X <= bp.X || (ap.X == bp.X && ap.Y <= bp.Y)) {
closePairs.Add(new Tuple<IHull, IHull>(a.UserData, b.UserData));
}
}
} else if (a.UserData == null && b.UserData == null) {
GetClosePairs(a.Left, b.Left, closePairs);
GetClosePairs(a.Left, b.Right, closePairs);
GetClosePairs(a.Right, b.Left, closePairs);
GetClosePairs(a.Right, b.Right, closePairs);
} else if (a.UserData == null) {
GetClosePairs(a.Left, b, closePairs);
GetClosePairs(a.Right, b, closePairs);
} else {
GetClosePairs(a, b.Left, closePairs);
GetClosePairs(a, b.Right, closePairs);
}
}
private IEnumerable<RectangleNode<IHull>> GetNodeRects(List<IHull> nodes) {
foreach (var v in nodes) {
yield return v.RectangleNode;
}
}
}
}