private void CollectSubtreeNodes(INode selectedNode, List <INode> nodesToDelete) { nodesToDelete.Add(selectedNode); IListEnumerable <IEdge> outEdges = graphControl.Graph.EdgesAt(selectedNode, AdjacencyTypes.Outgoing); foreach (IEdge outEdge in outEdges) { var target = (INode)outEdge.TargetPort.Owner; CollectSubtreeNodes(target, nodesToDelete); } }
private int GetLayer(INode n) { int layer = 0; INode node = n; while (true) { IListEnumerable <IEdge> inEdges = graphControl.Graph.EdgesAt(node, AdjacencyTypes.Incoming); if (inEdges.Count == 0) { break; } else { node = (INode)inEdges.First().SourcePort.Owner; layer++; } } return(layer); }
/// <summary> /// Runs a balloon layout where the hierarchy edges are the tree edges and original edges are bundled. /// </summary> private async Task RunBalloonLayout(IListEnumerable <INode> affectedNodes = null) { // create the balloon layout var layout = new BalloonLayout { IntegratedNodeLabeling = true, NodeLabelingPolicy = NodeLabelingPolicy.RayLikeLeaves, FromSketchMode = true, CompactnessFactor = 0.1, AllowOverlaps = true }; // prepend a TreeReduction stage with the hierarchy edges as tree edges layout.PrependStage(new TreeReductionStage()); var nonTreeEdges = GraphControl.Graph.Edges.Where(e => !aggregationHelper.IsHierarchyEdge(e)).ToList(); // mark all other edges to be bundled var bundleDescriptorMap = new ItemMapping <IEdge, EdgeBundleDescriptor>(); foreach (var nonTreeEdge in nonTreeEdges) { bundleDescriptorMap.Mapper[nonTreeEdge] = new EdgeBundleDescriptor { Bundled = true }; } var treeReductionStageData = new TreeReductionStageData { NonTreeEdges = { Items = nonTreeEdges }, EdgeBundleDescriptors = bundleDescriptorMap }; // create a layout executor that also zooms to all nodes that were affected by the last operation var layoutExecutor = new ZoomToNodesLayoutExecutor(affectedNodes ?? ListEnumerable <INode> .Empty, GraphControl, layout) { Duration = TimeSpan.FromSeconds(0.5), AnimateViewport = true, EasedAnimation = true, LayoutData = treeReductionStageData }; await layoutExecutor.Start(); }
private static IBend CreateBends([NotNull] IGraph graph, [NotNull] IEdge edge, int segmentIndex, double ratio, [NotNull] IListEnumerable <IPoint> pathPoints) { //Create 3 bends and adjust the neighbors //The first bend we need to touch is at startIndex var startIndex = segmentIndex * 3; //This holds the new coordinates left and right of the split point //We don't actually need all of them, but this keeps the algorithm more straightforward. var left = new PointD[4]; var right = new PointD[4]; //Determine the new control points to cleanly split the curve GetCubicSplitPoints(ratio, new[] { pathPoints[startIndex].ToPointD(), pathPoints[startIndex + 1].ToPointD(), pathPoints[startIndex + 2].ToPointD(), pathPoints[startIndex + 3].ToPointD() }, left, right); //Previous control point - does always exist as a bend, given our precondition var previousBend = edge.Bends[startIndex]; //Next control point - also always exists given the precondition for bend counts (i.e. there have to be at least two) var nextBend = edge.Bends[startIndex + 1]; //We create the three new bends between previous bend and next bend and adjust these two. //We don't have to adjust more bends, since we just have a cubic curve. IBend bendToMove; var engine = graph.GetUndoEngine(); //Wrap everything into a single compound edit, so that everything can be undone in a single unit using (var edit = graph.BeginEdit("Create Bezier Bend", "Create Bezier Bend")) { try { //Adjust the previous bend - given the split algorithm, its coordinate is in left[1] //(left[0] is actually kept unchanged from the initial value) var oldPrevLocation = previousBend.Location.ToPointD(); var newPrevLocation = left[1]; graph.SetBendLocation(previousBend, newPrevLocation); // Add unit to engine graph.AddUndoUnit("Set bend location", "Set bend location", () => graph.SetBendLocation(previousBend, oldPrevLocation), () => graph.SetBendLocation(previousBend, newPrevLocation)); //Insert the new triple, using the values from left and right in order graph.AddBend(edge, left[2], startIndex + 1); bendToMove = graph.AddBend(edge, left[3], startIndex + 2); //right[0] == left[3], so right[1] is the next new control point graph.AddBend(edge, right[1], startIndex + 3); //Adjust the next bend var oldNextLocation = nextBend.Location.ToPointD(); var newNextLocation = right[2]; graph.SetBendLocation(nextBend, newNextLocation); // Add unit to engine graph.AddUndoUnit("Set bend location", "Set bend location", () => graph.SetBendLocation(nextBend, oldNextLocation), () => graph.SetBendLocation(nextBend, newNextLocation)); } catch { //Cancel the edit in case anything goes wrong. edit.Cancel(); throw; } } return(bendToMove); }
public ZoomToNodesLayoutExecutor(IListEnumerable <INode> nodes, GraphControl graphControl, ILayoutAlgorithm layout) : base(graphControl, layout) { this.nodes = nodes; }