Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic Preventing node overlap (Read 4112 times)
fvkoss
YaBB Newbies
*
Offline


I Love MindFusion!

Posts: 3
Joined: Oct 1st, 2014
Preventing node overlap
Oct 1st, 2014 at 9:05pm
Print Post  
I've reviewed the documentation in the Placement and Layout section, but I don't see answers for this. I want to create a diagram such that no nodes ever intersect. If the user makes a node larger, I want the nodes that are now partially "covered" to be moved away from the resized node, and if the moved node(s) cover other nodes, them to be moved, etc. I only want the intersecting nodes to move, but not any nodes not directly impacted by the resize. Is there any automatic layout algorithm that will do this (or other API support)? I'm working in C#. Thanks in advance.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Preventing node overlap
Reply #1 - Oct 2nd, 2014 at 8:18am
Print Post  
Try applying SpringLayout with all but the intersected nodes set as Frozen:

Code
Select All
private void OnNodeModified(object sender, NodeEventArgs e)
{
	RemoveOverlaps(e.Node);
}

void RemoveOverlaps(DiagramNode modifiedNode)
{
	var overlaps = FindOverlaps(modifiedNode);
	if (overlaps.Count > 0)
	{
		foreach (var node in diagram.Nodes)
			node.LayoutTraits[SpringLayoutTraits.Frozen] = true;

		foreach (var node in overlaps)
			node.LayoutTraits[SpringLayoutTraits.Frozen] = false;

		var springLayout = new SpringLayout();
		springLayout.SplitGraph = false;
		springLayout.Randomize = false;
		springLayout.RepulsionFactor /= 2;
		springLayout.Arrange(diagram);

		foreach (var node in diagram.Nodes)
			node.LayoutTraits.Remove(SpringLayoutTraits.Frozen);
	}
}

List<DiagramNode> FindOverlaps(DiagramNode modifiedNode)
{
	var overlaps = new List<DiagramNode>();
	foreach (var node in diagram.Nodes)
	{
		if (modifiedNode == node)
			continue;
		if (modifiedNode.Bounds.IntersectsWith(node.Bounds))
			overlaps.Add(node);
	}
	return overlaps;
} 



I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
fvkoss
YaBB Newbies
*
Offline


I Love MindFusion!

Posts: 3
Joined: Oct 1st, 2014
Re: Preventing node overlap
Reply #2 - Oct 2nd, 2014 at 2:57pm
Print Post  
Thank you, but it's not quite working.  Nodes move too far.  I've tried playing with the various properties, but the intersected nodes still don't just move the few number of pixels they need to (need link strength and node repulsion to be near 0?).  I wish other layouts had a Frozen trait, because I think that might help another layout to work as desired.

Even if I can't get a built-in layout to work, your pattern for finding overlapping nodes in when a node is modified is very helpful.  Again, thanks.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Preventing node overlap
Reply #3 - Oct 2nd, 2014 at 5:38pm
Print Post  
SpringLayout.NodeDistance specifies desired distance between connected nodes, i.e. it's actually more like a link-length property, so you might add some temporary links if nodes aren't already connected to control the distance.

It's not hard to offset overlapped nodes without using layout classes, e.g. try something along these lines:

Code
Select All
private void OnNodeModified(object sender, NodeEventArgs e)
{
	RemoveOverlaps(e.Node, 20);
}

void RemoveOverlaps(DiagramNode modifiedNode, double minDist)
{
	var queue = new Queue<DiagramNode>();
	queue.Enqueue(modifiedNode);

	while (queue.Count > 0)
	{
		var node = queue.Dequeue();
		var nodeCenter = node.GetCenter();
		var overlaps = FindOverlaps(node, minDist);
		foreach (var overlap in overlaps)
		{
			var ovrCenter = overlap.GetCenter();
			var ovrBounds = overlap.Bounds;
			var dx = ovrCenter.X - nodeCenter.X;
			var dy = ovrCenter.Y - nodeCenter.Y;
			if (Math.Abs(dx) > Math.Abs(dy))
			{
				// offset horizontally
				if (dx < 0)
					ovrBounds.X = node.Bounds.Left - ovrBounds.Width - minDist;
				else
					ovrBounds.X = node.Bounds.Right + minDist;
			}
			else
			{
				// offset vertically
				if (dy < 0)
					ovrBounds.Y = node.Bounds.Top - ovrBounds.Height - minDist;
				else
					ovrBounds.Y = node.Bounds.Bottom + minDist;
			}

			// shifting the node might introduce new overlaps, continue processing
			overlap.Bounds = ovrBounds;
			queue.Enqueue(overlap);
		}
	}
}

List<DiagramNode> FindOverlaps(DiagramNode modifiedNode, double minDist)
{
	var bounds = modifiedNode.Bounds;
	bounds.Inflate(minDist - 1, minDist - 1);

	var overlaps = new List<DiagramNode>();
	foreach (var node in diagram.Nodes)
	{
		if (modifiedNode == node)
			continue;
		if (bounds.IntersectsWith(node.Bounds))
			overlaps.Add(node);
	}
	return overlaps;
} 



That method also propagates to remaining nodes to make sure shifted overlapped nodes do not introduce new overlaps.

I hope that helps,
Stoyan
« Last Edit: Oct 3rd, 2014 at 7:26am by Stoyo »  
Back to top
 
IP Logged
 
fvkoss
YaBB Newbies
*
Offline


I Love MindFusion!

Posts: 3
Joined: Oct 1st, 2014
Re: Preventing node overlap
Reply #4 - Oct 6th, 2014 at 7:53pm
Print Post  
I thought of something like that over the weekend, but you beat me to coding.  Thank you again!
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint