/// <summary> /// Example on how to use Stress Majorization with a small graph and Localized method. /// </summary> public static void RunStressMajorizationExample() { //create a star graph where three nodes are connected to the center GeometryGraph graph = new GeometryGraph(); graph.Nodes.Add(new Node()); graph.Nodes.Add(new Node()); graph.Nodes.Add(new Node()); graph.Nodes.Add(new Node()); //set initial positions, e.g., random graph.Nodes[0].BoundaryCurve = CurveFactory.CreateRectangle(20, 10, new Point(5, 5)); graph.Nodes[1].BoundaryCurve = CurveFactory.CreateRectangle(20, 10, new Point(7, 10)); graph.Nodes[2].BoundaryCurve = CurveFactory.CreateRectangle(20, 10, new Point(7, 2)); graph.Nodes[3].BoundaryCurve = CurveFactory.CreateRectangle(20, 10, new Point(35, 1)); graph.Edges.Add(new Edge(graph.Nodes[0], graph.Nodes[1])); graph.Edges.Add(new Edge(graph.Nodes[0], graph.Nodes[2])); graph.Edges.Add(new Edge(graph.Nodes[0], graph.Nodes[3])); //array with desired distances between the nodes for every edge double[] idealEdgeLength=new double[graph.Edges.Count]; for (int i = 0; i < graph.Edges.Count; i++) { idealEdgeLength[i] = 100; //all edges should have this euclidean length } //create stress majorization class and set the desired distances on the edges StressMajorization majorizer = new StressMajorization(); majorizer.Positions = new List<Point>(graph.Nodes.Select(v=>v.Center)); majorizer.NodeVotings = new List<NodeVoting>(graph.Nodes.Count); // initialize for every node an empty block for (int i = 0; i < graph.Nodes.Count; i++) { var nodeVote = new NodeVoting(i); //by default there is already a block with weighting 1 //optional: add second block with different type of edges, e.g., with stronger weight //var secondBlock = new VoteBlock(new List<Vote>(), 100); //nodeVote.VotingBlocks.Add(secondBlock); //var block2=nodeVote.VotingBlocks[1]; //block could be accessed like this in a later stage majorizer.NodeVotings.Add(nodeVote); } // for every edge set the desired distances by setting votings among the two end nodes. Dictionary<Node,int> posDict=new Dictionary<Node, int>(); for (int i = 0; i < graph.Nodes.Count; i++) { posDict[graph.Nodes[i]] = i; } var edges = graph.Edges.ToArray(); for (int i=0; i<graph.Edges.Count;i++) { var edge = edges[i]; int nodeId1 = posDict[edge.Source]; int nodeId2 = posDict[edge.Target]; double idealDistance = idealEdgeLength[i]; double weight = 1 / (idealDistance * idealDistance); var voteFromNode1 = new Vote(nodeId1, idealDistance, weight); // vote from node1 for node2 var voteFromNode2 = new Vote(nodeId2, idealDistance, weight); // vote from node2 for node1 // add vote of node1 to list of node2 (in first voting block) majorizer.NodeVotings[nodeId2].VotingBlocks[0].Votings.Add(voteFromNode1); // add vote of node2 to list of node1 (in first voting block) majorizer.NodeVotings[nodeId1].VotingBlocks[0].Votings.Add(voteFromNode2); } //used localized method to reduce stress majorizer.Settings=new StressMajorizationSettings(); majorizer.Settings.SolvingMethod=SolvingMethod.Localized; List<Point> result = majorizer.IterateAll(); for (int i = 0; i < result.Count; i++) { graph.Nodes[i].Center = result[i]; } #if DEBUG && !SILVERLIGHT && !SHARPKIT LayoutAlgorithmSettings.ShowGraph(graph); #endif }
static void AddStressFromProximityEdges(StressMajorization stressSolver, List<Tuple<int, int, double, double>> proximityEdgesWithDistance) { //set to check whether we already added forces between two nodes var nodePairs = new HashSet<Tuple<int, int>>(); // set the corresponding forces/votings foreach (var tuple in proximityEdgesWithDistance) { int nodeId1 = tuple.Item1; int nodeId2 = tuple.Item2; if (nodeId1 > nodeId2) { nodeId1 = tuple.Item2; nodeId2 = tuple.Item1; } var tup = new Tuple<int, int>(nodeId1, nodeId2); if (nodePairs.Contains(tup)) continue; nodePairs.Add(tup); double distance = tuple.Item3; double weight = 1/(distance*distance); var voteFromNode1 = new Vote(nodeId1, distance, weight); // vote from node1 for node2 var voteFromNode2 = new Vote(nodeId2, distance, weight); // vote from node2 for node1 if (tuple.Item4 <= 1) { //nodes do not overlap // add the votings, which represent forces, to the corresponding block. stressSolver.NodeVotings[nodeId2].VotingBlocks[0].Votings.Add(voteFromNode1); // add vote of node1 to list of node2 stressSolver.NodeVotings[nodeId1].VotingBlocks[0].Votings.Add(voteFromNode2); } else { //edges where nodes do overlap // add the votings, which represent forces, to the corresponding block. stressSolver.NodeVotings[nodeId2].VotingBlocks[1].Votings.Add(voteFromNode1); // add vote of node1 to list of node2 stressSolver.NodeVotings[nodeId1].VotingBlocks[1].Votings.Add(voteFromNode2); // add vote of node2 to list of node1 } } }