using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.Msagl.Core.DataStructures; using Microsoft.Msagl.Core.Geometry; namespace Microsoft.Msagl.Prototype.NonOverlappingBoundaries { /// /// 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 /// public interface IHull { /// /// Actual or weighted center of the hull /// Point Center { get; } /// /// /// /// void MoveCenter(Point delta); /// /// Bounding box /// RectangleNode RectangleNode { get; } /// /// Remove overlap between this and another IHull by moving them both as little as possible /// /// /// amount of displacement double Project(IHull other); } /// /// Uses Lev's HierarchyCalculatorWithRectangularNodes to do overlap queries /// internal class ProximityQuery { internal ProximityQuery(List nodeHulls) { hierarchy = RectangleNode.CreateRectangleNodeOnEnumeration(GetNodeRects(nodeHulls)); } /// /// Find all overlapping pairs. /// /// List of overlapping pairs internal List> GetAllIntersections() { List> closePairs = new List>(); GetClosePairs(hierarchy, hierarchy, closePairs); return closePairs; } private RectangleNode hierarchy; /// /// Search in the hierarchy for rectangles that intersect with leafNode. /// /// /// /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private void GetIntersecting(RectangleNode leafNode, RectangleNode internalNode, List 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 a, RectangleNode b, List> 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(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> GetNodeRects(List nodes) { foreach (var v in nodes) { yield return v.RectangleNode; } } } }