public static void Main() { DefaultLayoutGraph graph = new DefaultLayoutGraph(); //construct graph. assign sizes to nodes Node v1 = graph.CreateNode(); graph.SetSize(v1, 30, 30); Node v2 = graph.CreateNode(); graph.SetSize(v2, 30, 30); Node v3 = graph.CreateNode(); graph.SetSize(v3, 30, 30); // add a label to one node var nodeLabelLayoutModel = new DiscreteNodeLabelLayoutModel(DiscreteNodeLabelPositions.InternalMask, 4); var labelLayoutFactory = LayoutGraphUtilities.GetLabelFactory(graph); labelLayoutFactory.AddLabelLayout(v1, labelLayoutFactory.CreateLabelLayout(v1, new YOrientedRectangle(0, 0, 80, 20), nodeLabelLayoutModel)); Edge e1 = graph.CreateEdge(v1, v2); Edge e2 = graph.CreateEdge(v1, v3); // add a label to an edge var edgeLabelLayoutModel = new SliderEdgeLabelLayoutModel(SliderMode.Side); labelLayoutFactory.AddLabelLayout(e1, labelLayoutFactory.CreateLabelLayout(e1, new YOrientedRectangle(0, 0, 80, 20), edgeLabelLayoutModel, PreferredPlacementDescriptor.NewSharedInstance(LabelPlacements.LeftOfEdge))); //optionally setup some port constraints for HierarchicLayout IEdgeMap spc = graph.CreateEdgeMap(); IEdgeMap tpc = graph.CreateEdgeMap(); //e1 shall leave and enter the node on the right side spc.Set(e1, PortConstraint.Create(PortSide.East, false)); //additionally set a strong port constraint on the target side. tpc.Set(e1, PortConstraint.Create(PortSide.East, true)); //ports with strong port constraints will not be reset by the //layout algorithm. So we specify the target port right now to connect //to the upper left corner of the node graph.SetTargetPointRel(e1, new YPoint(15, -15)); //e2 shall leave and enter the node on the top side spc.Set(e2, PortConstraint.Create(PortSide.North, false)); tpc.Set(e2, PortConstraint.Create(PortSide.North, false)); graph.AddDataProvider(PortConstraintKeys.SourcePortConstraintDpKey, spc); graph.AddDataProvider(PortConstraintKeys.TargetPortConstraintDpKey, tpc); HierarchicLayout layout = new HierarchicLayout(); layout.IntegratedEdgeLabeling = true; layout.ConsiderNodeLabels = true; layout.LayoutMode = LayoutMode.FromScratch; new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH LAID OUT HIERARCHICALLY FROM SCRATCH"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); //display the graph in a simple viewer GraphViewer gv = new GraphViewer(); gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "Before Addition"); // now add a node and two edges incrementally... Node v4 = graph.CreateNode(); graph.SetSize(v4, 30, 30); Edge e4 = graph.CreateEdge(v4, v2); Edge e3 = graph.CreateEdge(v1, v4); //mark elements as newly added so that the layout algorithm can place //them nicely. IIncrementalHintsFactory ihf = layout.CreateIncrementalHintsFactory(); IDataMap map = Maps.CreateHashedDataMap(); map.Set(v4, ihf.CreateLayerIncrementallyHint(v4)); map.Set(e3, ihf.CreateSequenceIncrementallyHint(e3)); map.Set(e4, ihf.CreateSequenceIncrementallyHint(e4)); graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, map); layout.LayoutMode = LayoutMode.Incremental; new BufferedLayout(layout).ApplyLayout(graph); Console.WriteLine("\n\nGRAPH AFTER ELEMENTS HAVE BEEN ADDED INCREMENTALLY"); Console.WriteLine("v1 center position = " + graph.GetCenter(v1)); Console.WriteLine("v2 center position = " + graph.GetCenter(v2)); Console.WriteLine("v3 center position = " + graph.GetCenter(v3)); Console.WriteLine("v4 center position = " + graph.GetCenter(v4)); Console.WriteLine("e1 path = " + graph.GetPath(e1)); Console.WriteLine("e2 path = " + graph.GetPath(e2)); Console.WriteLine("e3 path = " + graph.GetPath(e3)); Console.WriteLine("e4 path = " + graph.GetPath(e4)); //clean up data maps graph.RemoveDataProvider(HierarchicLayout.IncrementalHintsDpKey); //display the graph in a simple viewer gv.AddLayoutGraph(new CopiedLayoutGraph(graph), "After Addition"); Application.Run(gv); }
///<inheritdoc/> protected override void ConfigureLayout() { LayoutGraph graph = CurrentLayoutGraph; HierarchicLayout hl = new HierarchicLayout(); LayoutAlgorithm = hl; // mark incremental elements if required IDataMap incrementalElements; OptionGroup generalGroup = (OptionGroup)Handler.GetGroupByName(GENERAL); OptionGroup currentGroup = (OptionGroup)generalGroup.GetGroupByName(INTERACTION); OptionGroup groupingGroup = (OptionGroup)Handler.GetGroupByName(GROUPING); bool fromSketch = (bool)currentGroup[USE_DRAWING_AS_SKETCH].Value; bool incrementalLayout = (bool)currentGroup[SELECTED_ELEMENTS_INCREMENTALLY].Value; bool selectedElements = !IsEdgeSelectionEmpty() || !IsNodeSelectionEmpty(); if (incrementalLayout && selectedElements) { // create storage for both nodes and edges incrementalElements = Maps.CreateHashedDataMap(); // configure the mode hl.LayoutMode = LayoutMode.Incremental; IIncrementalHintsFactory ihf = hl.CreateIncrementalHintsFactory(); foreach (Node node in graph.Nodes) { if (IsSelected(node)) { incrementalElements.Set(node, ihf.CreateLayerIncrementallyHint(node)); } } foreach (Edge edge in graph.Edges) { if (IsSelected(edge)) { incrementalElements.Set(edge, ihf.CreateSequenceIncrementallyHint(edge)); } } graph.AddDataProvider(HierarchicLayout.IncrementalHintsDpKey, incrementalElements); } else if (fromSketch) { hl.LayoutMode = LayoutMode.Incremental; } else { hl.LayoutMode = LayoutMode.FromScratch; } // cast to implementation simplex var np = (SimplexNodePlacer)hl.NodePlacer; np.BarycenterMode = (bool)generalGroup[SYMMETRIC_PLACEMENT].Value; np.StraightenEdges = (bool)Handler.GetValue(EDGE_SETTINGS, EDGE_STRAIGHTENING_OPTIMIZATION_ENABLED); hl.ComponentLayoutEnabled = (bool)generalGroup[LAYOUT_COMPONENTS_SEPARATELY].Value; currentGroup = (OptionGroup)generalGroup.GetGroupByName(MINIMUM_DISTANCES); hl.MinimumLayerDistance = (double)currentGroup[MINIMUM_LAYER_DISTANCE].Value; hl.NodeToEdgeDistance = (double)currentGroup[NODE_TO_EDGE_DISTANCE].Value; hl.NodeToNodeDistance = (double)currentGroup[NODE_TO_NODE_DISTANCE].Value; hl.EdgeToEdgeDistance = (double)currentGroup[EDGE_TO_EDGE_DISTANCE].Value; NodeLayoutDescriptor nld = hl.NodeLayoutDescriptor; EdgeLayoutDescriptor eld = hl.EdgeLayoutDescriptor; currentGroup = (OptionGroup)Handler.GetGroupByName(EDGE_SETTINGS); hl.AutomaticEdgeGrouping = (bool)currentGroup[AUTOMATIC_EDGE_GROUPING_ENABLED].Value; string edgeRoutingChoice = (string)currentGroup[EDGE_ROUTING].Value; eld.RoutingStyle = edgeRoutingEnum[edgeRoutingChoice]; eld.MinimumFirstSegmentLength = (double)currentGroup[MINIMUM_FIRST_SEGMENT_LENGTH].Value; eld.MinimumLastSegmentLength = (double)currentGroup[MINIMUM_LAST_SEGMENT_LENGTH].Value; eld.MinimumDistance = (double)currentGroup[MINIMUM_EDGE_DISTANCE].Value; eld.MinimumLength = (double)currentGroup[MINIMUM_EDGE_LENGTH].Value; eld.MinimumSlope = (double)currentGroup[MINIMUM_SLOPE].Value; eld.SourcePortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value; eld.TargetPortOptimization = (bool)currentGroup[PC_OPTIMIZATION_ENABLED].Value; var isIncrementalModeEnabled = (fromSketch || (incrementalLayout && selectedElements)); var recursiveRoutingMode = Handler.GetValue(EDGE_SETTINGS, RECURSIVE_EDGE_ROUTING); if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_DIRECTED) { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Directed; } else if (!isIncrementalModeEnabled && recursiveRoutingMode == RECURSIVE_EDGE_ROUTING_UNDIRECTED) { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Undirected; } else { eld.RecursiveEdgeStyle = RecursiveEdgeStyle.Off; } nld.MinimumDistance = Math.Min(hl.NodeToNodeDistance, hl.NodeToEdgeDistance); nld.MinimumLayerHeight = 0; OptionGroup rankGroup = (OptionGroup)Handler.GetGroupByName(RANKS); string layerAlignmentChoice = (string)rankGroup[LAYER_ALIGNMENT].Value; nld.LayerAlignment = alignmentEnum[layerAlignmentChoice]; ol = (OrientationLayout)hl.OrientationLayout; string orientationChoice = (string)generalGroup[ORIENTATION].Value; ol.Orientation = orientEnum[orientationChoice]; OptionGroup labelingGroup = (OptionGroup)Handler.GetGroupByName(LABELING); currentGroup = (OptionGroup)labelingGroup.GetGroupByName(LABELING_EDGE_PROPERTIES); string el = (string)currentGroup[EDGE_LABELING].Value; if (!el.Equals(EDGE_LABELING_NONE)) { if (el.Equals(EDGE_LABELING_GENERIC)) { var la = new GenericLabeling(); la.MaximumDuration = 0; la.PlaceNodeLabels = false; la.PlaceEdgeLabels = true; la.AutoFlipping = true; la.ProfitModel = new SimpleProfitModel(); hl.PrependStage(la); } else if (el.Equals(EDGE_LABELING_HIERARCHIC)) { bool copactEdgeLabelPlacement = (bool)currentGroup[COMPACT_EDGE_LABEL_PLACEMENT].Value; if (hl.NodePlacer is SimplexNodePlacer) { np.LabelCompaction = copactEdgeLabelPlacement; } hl.IntegratedEdgeLabeling = true; } } else { hl.IntegratedEdgeLabeling = false; } currentGroup = (OptionGroup)labelingGroup.GetGroupByName(NODE_PROPERTIES); if ((bool)currentGroup[CONSIDER_NODE_LABELS].Value) { hl.ConsiderNodeLabels = true; hl.NodeLayoutDescriptor.NodeLabelMode = NodeLabelMode.ConsiderForDrawing; } else { hl.ConsiderNodeLabels = false; } string rp = (string)rankGroup[RANKING_POLICY].Value; hl.FromScratchLayeringStrategy = rankingPolicies[rp]; if (rp.Equals(BFS_LAYERS)) { CurrentLayoutGraph.AddDataProvider(BFSLayerer.CoreNodesDpKey, new SelectedNodesDP(this)); } hl.ComponentArrangementPolicy = componentAlignmentEnum[(string)rankGroup[COMPONENT_ARRANGEMENT_POLICY].Value]; //configure AsIsLayerer Object layerer = (hl.LayoutMode == LayoutMode.FromScratch) ? hl.FromScratchLayerer : hl.FixedElementsLayerer; // if (layerer is OldLayererWrapper) { // layerer = ((OldLayererWrapper)layerer).OldLayerer; // } if (layerer is AsIsLayerer) { AsIsLayerer ail = (AsIsLayerer)layerer; currentGroup = (OptionGroup)rankGroup.GetGroupByName(FROM_SKETCH_PROPERTIES); ail.NodeHalo = (double)currentGroup[HALO].Value; ail.NodeScalingFactor = (double)currentGroup[SCALE].Value; ail.MinimumNodeSize = (double)currentGroup[MINIMUM_SIZE].Value; ail.MaximumNodeSize = (double)currentGroup[MAXIMUM_SIZE].Value; } //configure grouping np.GroupCompactionStrategy = groupHorizCompactionEnum[(string)groupingGroup[GROUP_HORIZONTAL_COMPACTION].Value]; if (!fromSketch && groupStrategyEnum[(string)groupingGroup[GROUP_LAYERING_STRATEGY].Value]) { GroupAlignmentPolicy alignmentPolicy = groupAlignmentEnum[(string)groupingGroup[GROUP_ALIGNMENT].Value]; hl.GroupAlignmentPolicy = alignmentPolicy; hl.CompactGroups = (bool)groupingGroup[GROUP_ENABLE_COMPACTION].Value; hl.RecursiveGroupLayering = true; } else { hl.RecursiveGroupLayering = false; } OptionGroup swimGroup = (OptionGroup)Handler.GetGroupByName(SWIMLANES); if ((bool)swimGroup[TREAT_ROOT_GROUPS_AS_SWIMLANES].Value) { TopLevelGroupToSwimlaneStage stage = new TopLevelGroupToSwimlaneStage(); stage.OrderSwimlanesFromSketch = (bool)swimGroup[USE_ORDER_FROM_SKETCH].Value; stage.Spacing = (double)swimGroup[SWIMLANE_SPACING].Value; hl.AppendStage(stage); } hl.BackLoopRouting = (bool)Handler.GetValue(EDGE_SETTINGS, BACKLOOP_ROUTING); hl.MaximumDuration = ((int)Handler.GetValue(GENERAL, MAXIMUM_DURATION)) * 1000; bool gridEnabled = (bool)Handler.GetValue(GRID, GRID_ENABLED); if (gridEnabled) { hl.GridSpacing = (double)Handler.GetValue(GRID, GRID_SPACING); String portAssignment = (string)Handler.GetValue(GRID, GRID_PORT_ASSIGNMENT); PortAssignmentMode gridPortAssignment; switch (portAssignment) { case GRID_PORT_ASSIGNMENT_ON_GRID: gridPortAssignment = PortAssignmentMode.OnGrid; break; case GRID_PORT_ASSIGNMENT_ON_SUBGRID: gridPortAssignment = PortAssignmentMode.OnSubgrid; break; default: gridPortAssignment = PortAssignmentMode.Default; break; } graph.AddDataProvider(HierarchicLayoutCore.NodeLayoutDescriptorDpKey, new NodeLayoutDescriptorAdapter(hl.NodeLayoutDescriptor, graph, gridPortAssignment)); } }