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;
}
}
}
}