/// <summary> /// /// </summary> /// <param name="graph"></param> public void RemoveOverlaps(GeometryGraph graph) { Graph = graph; RemoveOverlaps(); }
/// <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 && !SHARPKIT // LayoutAlgorithmSettings.ShowGraph(graph); // #endif }
/// <summary> /// Constructor /// </summary> public ProximityOverlapRemoval(OverlapRemovalSettings settings, GeometryGraph graph) { Graph = graph; Settings = settings; }
/// <summary> /// /// </summary> /// <param name="graph"></param> public void RemoveOverlaps(GeometryGraph graph) { Graph = graph; RemoveOverlaps(); }
/// <summary> /// Computes distances between a selected set of nodes and all nodes. /// Pivot nodes are selected with maxmin strategy (first at random, later /// ones to maximize distances to all previously selected ones). /// </summary> /// <param name="graph">A graph.</param> /// <param name="directed">Whether shortest paths are directed.</param> /// <param name="pivotArray">Number of pivots.</param> public PivotDistances(GeometryGraph graph, bool directed, int[] pivotArray) { this.graph = graph; this.directed = directed; this.pivotArray = pivotArray; }
/// <summary> /// /// </summary> /// <param name="graph"></param> public SweeplineNestedRingTester(GeometryGraph graph) { this.graph = graph; }
/// <summary> /// Constructor /// </summary> /// <param name="graph"></param> public ProximityOverlapRemoval(GeometryGraph graph) { Graph = graph; InitializeSettings(); }
/// <summary> /// Dijkstra algorithm. Computes graph-theoretic distances from a node to /// all other nodes in a graph with nonnegative edge lengths. /// The distance between a node and itself is 0; the distance between a pair of /// nodes for which no connecting path exists is Double.PositiveInfinity. /// </summary> /// <param name="graph">A graph.</param> /// <param name="source">The source node.</param> /// <param name="directed">Whether the graph is directed.</param> public SingleSourceDistances(GeometryGraph graph, Node source) { this.graph = graph; this.source = source; }
internal GeometryGraph Create() { var msaglGraph = new GeometryGraph(); return(FillGraph(msaglGraph)); }
/// <summary> /// Recursively lay out the clusters of the given graph using the given settings. /// </summary> /// <param name="graph">The graph being operated on.</param> /// <param name="defaultSettings">Settings to use if none is provided for a particular cluster or its ancestors.</param> public InitialLayoutByCluster(GeometryGraph graph, LayoutAlgorithmSettings defaultSettings) : this(graph, anyCluster => defaultSettings) { }
public InitialLayoutByCluster(GeometryGraph graph, Func <Cluster, LayoutAlgorithmSettings> clusterSettings) : this(graph, new[] { graph.RootCluster }, clusterSettings) { }
private static void AddNode(string id, GeometryGraph graph, double w, double h) { graph.Nodes.Add(new Node(CreateCurve(w, h), id)); }
static internal GeometryGraph CreateAndLayoutGraph() { GeometryGraph graph = new GeometryGraph(); double width = 40; double height = 10; foreach (string id in "0 1 2 3 4 5 6 A B C D E F G a b c d e".Split(' ')) { AddNode(id, graph, width, height); } graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("B"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("C"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("D"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("E"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("B"), graph.FindNodeByUserData("E"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("0"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("1"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("2"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("3"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("4"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("5"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("6"), graph.FindNodeByUserData("F"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("a"), graph.FindNodeByUserData("b"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("b"), graph.FindNodeByUserData("c"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("c"), graph.FindNodeByUserData("d"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("d"), graph.FindNodeByUserData("e"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("A"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("B"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("C"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("D"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("E"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("F"), graph.FindNodeByUserData("a"))); graph.Edges.Add(new Edge(graph.FindNodeByUserData("G"), graph.FindNodeByUserData("a"))); var settings = new SugiyamaLayoutSettings(); settings.Transformation = PlaneTransformation.Rotation(Math.PI / 2); settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; var layout = new LayeredLayout(graph, settings); layout.Run(); return(graph); // double w = 40; // double h = 10; // GeometryGraph graph = new GeometryGraph(); //columns // var col0 = new[] { "a", "b", "c" }; // var col1 = new[] { "d", "e", "f", "g" }; // var col2 = new[] { "k", "l", "m", "n" }; // var col3 = new[] { "w", "y", "z" }; // // var settings = new SugiyamaLayoutSettings(); // // foreach (var id in col0) // AddNode(id, graph, w, h); // foreach (var id in col1) // AddNode(id, graph, w, h); // foreach (var id in col2) // AddNode(id, graph, w, h); // foreach (var id in col3) // AddNode(id, graph, w, h); // //pinning columns // settings.PinNodesToSameLayer(col0.Select(s=>graph.FindNodeByUserData(s)).ToArray()); // settings.PinNodesToSameLayer(col1.Select(s => graph.FindNodeByUserData(s)).ToArray()); // settings.PinNodesToSameLayer(col2.Select(s => graph.FindNodeByUserData(s)).ToArray()); // settings.PinNodesToSameLayer(col3.Select(s => graph.FindNodeByUserData(s)).ToArray()); // // AddEdgesBetweenColumns(col0, col1, graph); // AddEdgesBetweenColumns(col1, col2, graph); // AddEdgesBetweenColumns(col2, col3, graph); //rotate layer to columns // graph.Transformation = PlaneTransformation.Rotation(Math.PI / 2); // settings.NodeSeparation = 5; // settings.LayerSeparation = 100; // var ll = new LayeredLayout(graph, settings); // ll.Run(); // return graph; }
internal void AddConnectedGeomGraph(GeometryGraph geomGraph) { _connectedComponents.Add(geomGraph); }
private static void LayoutAndValidate(GeometryGraph graph, SugiyamaLayoutSettings settings, double nodeSeparation) { LayoutAndValidate(graph, settings, nodeSeparation, LayerDirection.TopToBottom); }
/// <summary> /// create a geometry edge, the geometry source and target have to be set already /// </summary> /// <param name="drawingEdge"></param> /// <param name="msaglGraph"></param> /// <returns></returns> static Core.Layout.Edge CreateGeometryEdgeAndAddItToGeometryGraph(Edge drawingEdge, GeometryGraph msaglGraph) { var msaglEdge = CreateGeometryEdgeFromDrawingEdge(drawingEdge); msaglGraph.Edges.Add(msaglEdge); return(msaglEdge); }
internal LgData(GeometryGraph mainGeomGraph) { this.mainGeomGraph = mainGeomGraph; }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object can be used to retrieve data from input parameters and /// to store data in output parameters.</param> protected override void SolveInstance(IGH_DataAccess DA) { try { //Extract the parameter data var floors = new List <Line>(); var walls = new List <Line>(); var ceilings = new List <Line>(); var elecTargets = new List <Grasshopper.Kernel.Types.GH_Point>(); var elecSource = new Grasshopper.Kernel.Types.GH_Point(); var floorMulti = 0.0; var wallMulti = 0.0; var ceilingMulti = 0.0; if (!DA.GetDataList(0, floors)) { return; } if (!DA.GetDataList(1, walls)) { return; } if (!DA.GetDataList(2, ceilings)) { return; } if (!DA.GetDataList(3, elecTargets)) { return; } if (!DA.GetData(4, ref elecSource)) { return; } if (!DA.GetData(5, ref floorMulti)) { return; } if (!DA.GetData(6, ref wallMulti)) { return; } if (!DA.GetData(7, ref ceilingMulti)) { return; } //build the graph along with a geometry -> edge/node map var graph = new GeometryGraph(floors, floorMulti, walls, wallMulti, ceilings, ceilingMulti); //get the corresponding node for the electric source if (!PathFindUtil.TryGetElectricNodes(DA, graph, elecSource, elecTargets, out var elecSourceNode, out var elecTargetNodes)) { DA.SetDataList(0, null); DA.SetData(1, "Failed to find source on graph"); } //find the shortest pats var res = graph.SolvePathFind(FindPathType.AStar, elecSourceNode, elecTargetNodes); //build the data tree with all of the paths var tree = PathFindUtil.BuildTree(res); DA.SetDataTree(0, tree); DA.SetData(1, "Success!"); } catch (Exception x) { DA.SetDataList(0, null); DA.SetData(1, $"M: {x.Message} - S: {x.StackTrace}"); } }
/// <summary> /// For a given graph finds the obstacles for nodes and clusters, correctly parenting the obstacles /// according to the cluster hierarchy /// </summary> /// <param name="graph">graph with edges to route and nodes/clusters to route around</param> /// <returns>the set of obstacles with correct cluster hierarchy and ports</returns> public static IEnumerable <Shape> GetShapes(GeometryGraph graph) { var nodesToShapes = new Dictionary <Node, Shape>(); var interestingNodes = graph.Nodes.Where(n => !n.UnderCollapsedCluster()).ToArray(); foreach (var v in interestingNodes) { nodesToShapes[v] = CreateShapeWithCenterPort(v); } foreach (var c in graph.RootCluster.AllClustersDepthFirst()) { if (!c.IsCollapsed) { foreach (var v in c.Nodes) { if (!nodesToShapes.ContainsKey(v)) { nodesToShapes[v] = CreateShapeWithCenterPort(v); } } } if (c == graph.RootCluster) { continue; } var parent = nodesToShapes[c] = CreateShapeWithClusterBoundaryPort(c); if (c.IsCollapsed) { continue; } foreach (var v in c.Nodes) { parent.AddChild(nodesToShapes[v]); } foreach (var d in c.Clusters) { parent.AddChild(nodesToShapes[d]); } } foreach (var edge in graph.Edges) { Shape shape; if (nodesToShapes.TryGetValue(edge.Source, out shape)) { if (edge.SourcePort != null) { shape.Ports.Insert(edge.SourcePort); } } if (nodesToShapes.TryGetValue(edge.Target, out shape)) { if (edge.TargetPort != null) { shape.Ports.Insert(edge.TargetPort); } } } return(nodesToShapes.Values); }
/// <summary> /// /// </summary> /// <param name="geometryGraph"></param> public ObjectDragUndoRedoAction(GeometryGraph geometryGraph) : base(geometryGraph) { }
/// <summary> /// This method can directly be called to resolve overlaps on a graph with a given node separationl. /// </summary> /// <param name="geometryGraph"></param> /// <param name="nodeSeparation"></param> public static void RemoveOverlaps(GeometryGraph geometryGraph, double nodeSeparation) { var prism = new ProximityOverlapRemoval(geometryGraph) {Settings = {NodeSeparation = nodeSeparation}}; prism.RemoveOverlaps(); }
internal UndoRedoAction(GeometryGraph graphPar) { this.Graph = graphPar; this.graphBoundingBoxBefore = this.Graph.BoundingBox; }
/// <summary> /// /// </summary> /// <param name="zoomLevel"></param> /// <param name="geomGraph">needed only for statistics</param> internal LgLevel(int zoomLevel, GeometryGraph geomGraph) { _geomGraph = geomGraph; ZoomLevel = zoomLevel; }
/// <summary> /// Create the graph data structures. /// </summary> /// <param name="geometryGraph"></param> /// <param name="settings">The settings for the algorithm.</param> /// <param name="initialConstraintLevel">initialize at this constraint level</param> /// <param name="clusterSettings">settings by cluster</param> internal FastIncrementalLayout(GeometryGraph geometryGraph, FastIncrementalLayoutSettings settings, int initialConstraintLevel, Func <Cluster, LayoutAlgorithmSettings> clusterSettings) { graph = geometryGraph; this.settings = settings; this.clusterSettings = clusterSettings; int i = 0; ICollection <Node> allNodes = graph.Nodes; nodes = new FiNode[allNodes.Count]; foreach (Node v in allNodes) { v.AlgorithmData = nodes[i] = new FiNode(i, v); i++; } clusterEdges.Clear(); edges.Clear(); foreach (Edge e in graph.Edges) { if (e.Source is Cluster || e.Target is Cluster) { clusterEdges.Add(e); } else { edges.Add(new FiEdge(e)); } foreach (var l in e.Labels) { l.InnerPoints = l.OuterPoints = null; } } SetLockNodeWeights(); components = new List <FiNode[]>(); if (!settings.InterComponentForces) { basicGraph = new BasicGraph <FiEdge>(edges, nodes.Length); foreach (var componentNodes in ConnectedComponentCalculator <FiEdge> .GetComponents(basicGraph)) { var vs = new FiNode[componentNodes.Count()]; int vi = 0; foreach (int v in componentNodes) { vs[vi++] = nodes[v]; } components.Add(vs); } } else // just one big component (regardless of actual edges) { components.Add(nodes); } horizontalSolver = new AxisSolver(true, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps, settings.MinConstraintLevel, clusterSettings) { OverlapRemovalParameters = new OverlapRemovalParameters { AllowDeferToVertical = true, // use "ProportionalOverlap" mode only when iterative apply forces layout is being used. // it is not necessary otherwise. ConsiderProportionalOverlap = settings.ApplyForces } }; verticalSolver = new AxisSolver(false, nodes, new[] { geometryGraph.RootCluster }, settings.AvoidOverlaps, settings.MinConstraintLevel, clusterSettings); SetupConstraints(); geometryGraph.RootCluster.ComputeWeight(); foreach ( Cluster c in geometryGraph.RootCluster.AllClustersDepthFirst().Where(c => c.RectangularBoundary == null) ) { c.RectangularBoundary = new RectangularClusterBoundary(); } CurrentConstraintLevel = initialConstraintLevel; }
/// <summary> /// /// </summary> /// <param name="geomGraph"></param> public ConsistentAreaTester(GeometryGraph geomGraph) { this.geomGraph = geomGraph; }
/// <summary> /// Constructs the multidimensional scaling algorithm. /// </summary> public MdsGraphLayout(MdsLayoutSettings settings, GeometryGraph geometryGraph) { this.settings = settings; graph = geometryGraph; }
/// <summary> /// saves the graph to a file /// </summary> public static void Write(GeometryGraph graph, string fileName) { Write(graph, null, fileName); }
public static void MDS() { WriteMessage("Starting test..."); WriteMessage("Create GeometryGraph"); GeometryGraph graph = AbcdeGraph(); //graph.Save("c:\\tmp\\saved.msagl"); var settings = new MdsLayoutSettings(); settings.RunInParallel = false; settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Rectilinear; LayoutHelpers.CalculateLayout(graph, settings, null); WriteMessage("Layout progressed"); WriteMessage(""); WriteMessage("Segments A->B"); //OutputCurve(ab.Curve); WriteMessage(""); WriteMessage("Segments B->C"); //OutputCurve(bc.Curve); WriteMessage(""); WriteMessage("Segments C->A"); //OutputCurve(ca.Curve); foreach (var node in graph.Nodes) { WriteMessage(string.Format("{0}: {1} {2}", node.UserData, node.Center.X, node.Center.Y)); } /*var canvas = HtmlContext.document.getElementById("drawing").As<HtmlCanvasElement>(); * var ctx = canvas.getContext("2d").As<CanvasRenderingContext2D>(); * * var canvasHeight = canvas.height; * * var bounds = calcBounds(graph.Nodes); * * var xScale = canvas.width / bounds.Width; * var yScale = canvas.height / bounds.Height; * * var xShift = -bounds.Left * xScale; * var yShift = -(canvas.height - bounds.Top) * yScale; * * WriteMessage(string.Format("Scaling : {0} {1}", xScale, yScale)); * WriteMessage(string.Format("Shifting : {0} {1}", xShift, yShift)); * * foreach (var msaglEdge in graph.Edges) * { * DrawEdge(ctx, msaglEdge, xShift, yShift, xScale, yScale, canvasHeight); * } * * foreach (var msaglNode in graph.Nodes) * { * DrawNode(ctx, msaglNode, xShift, yShift, xScale, yScale, canvasHeight); * }*/ }
/// <summary> /// Constructor /// </summary> /// <param name="graph"></param> public ProximityOverlapRemoval(GeometryGraph graph) { Graph = graph; InitializeSettings(); }
public static void LayeredLayoutAbc() { double w = 30; double h = 20; GeometryGraph graph = new GeometryGraph(); MSAGLNode a = new MSAGLNode(new Ellipse(w, h, new Point()), "a"); MSAGLNode b = new MSAGLNode(CurveFactory.CreateRectangle(w, h, new Point()), "b"); MSAGLNode c = new MSAGLNode(CurveFactory.CreateRectangle(w, h, new Point()), "c"); graph.Nodes.Add(a); graph.Nodes.Add(b); graph.Nodes.Add(c); Edge ab = new Edge(a, b) { Length = 10 }; Edge bc = new Edge(b, c) { Length = 3 }; graph.Edges.Add(ab); graph.Edges.Add(bc); var settings = new SugiyamaLayoutSettings(); LayoutHelpers.CalculateLayout(graph, settings, null); WriteMessage("Layout progressed"); /*WriteMessage(""); * WriteMessage("Segments A->B"); * //OutputCurve(ab.Curve); * * WriteMessage(""); * WriteMessage("Segments B->C"); * //OutputCurve(bc.Curve); * * WriteMessage(""); * WriteMessage("Segments C->A"); * //OutputCurve(ca.Curve); * * foreach (var node in graph.Nodes) * { * WriteMessage(string.Format("{0}: {1} {2}", node.UserData, node.Center.X, node.Center.Y)); * }*/ /*var canvas = HtmlContext.document.getElementById("drawing").As<HtmlCanvasElement>(); * var ctx = canvas.getContext("2d").As<CanvasRenderingContext2D>(); * * var canvasHeight = canvas.height; * * var bounds = calcBounds(graph.Nodes); * * var xScale = canvas.width / bounds.Width; * var yScale = canvas.height / bounds.Height; * * var xShift = -bounds.Left * xScale; * var yShift = -(canvas.height - bounds.Top) * yScale; * * WriteMessage(string.Format("Scaling : {0} {1}", xScale, yScale)); * WriteMessage(string.Format("Shifting : {0} {1}", xShift, yShift)); * * foreach (var msaglEdge in graph.Edges) * { * DrawEdge(ctx, msaglEdge, xShift, yShift, xScale, yScale, canvasHeight); * } * * foreach (var msaglNode in graph.Nodes) * { * DrawNode(ctx, msaglNode, xShift, yShift, xScale, yScale, canvasHeight); * }*/ }
private static void LayoutAndValidate(GeometryGraph graph, SugiyamaLayoutSettings settings, LayerDirection direction) { LayoutAndValidate(graph, settings, settings.NodeSeparation, settings.LayerSeparation, direction); }
/// <summary> /// Find a point from the list of testCoords /// that is NOT a node in the edge for the list of searchCoords. /// </summary> /// <param name="testCoords"></param> /// <param name="searchRing"></param> /// <param name="graph"></param> /// <returns>The point found, or <c>null</c> if none found.</returns> public static Coordinate FindPointNotNode(Coordinate[] testCoords, LinearRing searchRing, GeometryGraph graph) { // find edge corresponding to searchRing. var searchEdge = graph.FindEdge(searchRing); // find a point in the testCoords which is not a node of the searchRing var eiList = searchEdge.EdgeIntersectionList; // somewhat inefficient - is there a better way? (Use a node map, for instance?) foreach (var pt in testCoords) { if (!eiList.IsIntersection(pt)) { return(pt); } } return(null); }
/// <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 }
/// <summary> /// /// </summary> /// <param name="geomGraph"></param> public ConnectedInteriorTester(GeometryGraph geomGraph) { _geomGraph = geomGraph; }