Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic Rearrange and Layered Layout ! (Read 10370 times)
yrauma
Junior Member
**
Offline


I love YaBB 1G - SP1!

Posts: 61
Joined: Mar 28th, 2010
Rearrange and Layered Layout !
Mar 1st, 2012 at 11:23pm
Print Post  
Hello !

Following this thread : http://mindfusion.eu/Forum/YaBB.pl?board=fcnet_disc;action=display;num=132149127... I am posting a request concerning Layered Layout and FCNet for WinForms.

We are heavily using containers and node with custom drawing and size.

There is no real rule in our graph despite the fact that there is always a single root on our tree but the nodes in our containers can be at various level.

Currently when we do a rearrange (using this method: http://mindfusion.eu/Forum/YaBB.pl?board=fcnet_disc;action=display;num=127351559...) we have this:



This is done using a random graph (just one we know does not work).
Our problem here is that Links does intercell with each other outside of the container. At this scale it is not that bad but with bigger graphs it can get very confusing.

What we need after the rearrange is this:


Could you guys fix that for us or give us a new layout that will more fits our need ?

Thanks !

yrauma.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Rearrange and Layered Layout !
Reply #1 - Mar 5th, 2012 at 11:57am
Print Post  
We can't think of any way to arrange containers with minimized link crossings without knowing what kind of content they have. If the container contains a row of nodes without links between them as in your screenshot, you can use the SortByIncomingLinks method below to sort them and eliminate crossings of external links.

If the containers' content is completely arbitrary, e.g. with child nodes connected too, you could use the constrained spring layout method shown to arrange them. This method depends on the initial container size so you might have to set some container.Bounds size appropriate for the number of its children before running it. Also if the container has a lot of children, you might have to increase the number of SpringLayout iterations.

Code
Select All
Arrange(diagram, outerLayout, innerLayout);
SortByIncomingLinks();
//ConstrainedSpringLayout();

void SortByIncomingLinks()
{
	foreach (DiagramNode node in diagram.Nodes)
	{
		ContainerNode ctr = node as ContainerNode;
		if (ctr != null)
			SortByIncomingLinks(ctr);
	}
}

void SortByIncomingLinks(ContainerNode ctr)
{
	List<DiagramNode> children = new List<DiagramNode>();
	foreach (DiagramNode node in ctr.SubordinateGroup.AttachedNodes)
		children.Add(node);
	children.Sort(CompareByInLinks);

	float x = ctr.Bounds.X + 5;
	foreach (DiagramNode node in children)
	{
		node.Move(x, node.Bounds.Y);
		x = node.Bounds.Right + 5;
	}
}

int CompareByInLinks(DiagramNode n1, DiagramNode n2)
{
	DiagramLink link1 = null;
	if (n1.IncomingLinks.Count > 0)
		link1 = n1.IncomingLinks[0];
	DiagramLink link2 = null;
	if (n2.IncomingLinks.Count > 0)
		link2 = n2.IncomingLinks[0];

	if (link1 != null && link2 == null)
		return -1;
	if (link1 == null && link2 != null)
		return 1;
	if (link1 == null && link2 == null)
		return 0;

	PointF p1 = link1.ControlPoints[link1.ControlPoints.Count - 2];
	PointF p2 = link2.ControlPoints[link2.ControlPoints.Count - 2];
	return p1.X.CompareTo(p2.X);
}

void ConstrainedSpringLayout()
{
	foreach (DiagramNode node in diagram.Nodes)
	{
		ContainerNode ctr = node as ContainerNode;
		if (ctr != null)
			ConstrainedSpringLayout(ctr);
	}
}

void ConstrainedSpringLayout(ContainerNode ctr)
{
	DiagramItemCollection childNodesAndLinks = GetContainerItems(ctr);

	// find external nodes connected to nodes in the container
	List<DiagramNode> externalNodes = new List<DiagramNode>();
	List<DiagramLink> externalLinks = new List<DiagramLink>();
	foreach (DiagramItem item in childNodesAndLinks)
	{
		DiagramNode node = item as DiagramNode;
		if (node == null)
			continue;
		foreach (DiagramLink link in node.GetAllLinks())
		{
			DiagramNode adjacent = GetOtherEnd(link, node);
			if (!childNodesAndLinks.Contains(adjacent))
			{
				externalNodes.Add(adjacent);
				externalLinks.Add(link);
			}
		}
	}

	// set the frozen flag on the external nodes to prevent spring layout from moving them
	foreach (DiagramNode node in externalNodes)
	{
		node.LayoutTraits[SpringLayoutTraits.Frozen] = true;
		childNodesAndLinks.Add(node);
	}
	foreach (DiagramLink link in externalLinks)
		childNodesAndLinks.Add(link);

	RectangleF layoutRect = ctr.Bounds;
	layoutRect.Y += ctr.CaptionHeight;
	layoutRect.Height -= ctr.CaptionHeight;
	layoutRect.Inflate(-5, -5);

	SpringLayout layout = new SpringLayout();
	layout.LayoutArea = layoutRect;
	layout.SplitGraph = false;
	layout.Arrange(diagram, childNodesAndLinks);
} 



The attached image shows the result of ConstrainedSpringLayout.

You could analyze the content of each node and choose which method to use based on it, and also add handling for other special cases when you think they can be arranged better than the force-directed method does.

I hope that helps,
Stoyan
  

ctr_spring_layout.png (Attachment deleted)
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint