public override CircularNetwork MakeNetwork(IEnumerable <Node> nodes, IEnumerable <Link> links) { CircularNetwork net = base.MakeNetwork(nodes, links); // assume each Node has a constant diameter, ignoring any TextBlock double dia = 20; foreach (CircularVertex v in net.Vertexes) { v.Diameter = dia; } return(net); }
/// <summary> /// Do a circular layout. /// </summary> /// <remarks> /// </remarks> public override void DoLayout(IEnumerable<Node> nodes, IEnumerable<Link> links) { // Create Network if (this.Network == null) { this.Network = MakeNetwork(nodes, links); } // If there's only one node, put it at the origin if (this.Network.Vertexes.Count() == 1) { CircularVertex cv = this.Network.Vertexes.ElementAt(0); cv.Center = new Point(0, 0); return; } List<CircularVertex> vertices; List<CircularVertex> evens; // for bidirectionals, nodes of even index are usually arranged separately from odd index nodes List<CircularVertex> odds; // this also sets all of the E... "Effective" canonicalized property values SetEffectiveValues(out vertices, out evens, out odds); if ((this.Direction == CircularDirection.BidirectionalLeft || this.Direction == CircularDirection.BidirectionalRight) && EArrangement == CircularArrangement.Packed) { // if Arrangement == Packed and Direction is bidirectional, this is achieved by using a rearrangement of the vertices, and shifting the StartAngle PackedLayout(vertices, ESweepAngle, EStartAngle - ESweepAngle / 2, CircularDirection.Clockwise); } else if (this.Direction == CircularDirection.BidirectionalLeft || this.Direction == CircularDirection.BidirectionalRight) { double dsa = 0; // change in start angle // bidirectionals are achieved by laying out the even nodes in one direction, then laying out the odds in the opposite direction. // StartAngles must be slightly different. The switch below computes the difference switch (this.EArrangement) { case CircularArrangement.ConstantDistance: dsa = EllipseAngle(ERadius, Yradius, EStartAngle, constdist) * 180 / Math.PI; break; case CircularArrangement.ConstantSpacing: { double evendia = 0; double odddia = 0; CircularVertex firsteven = evens.FirstOrDefault(); if (firsteven != null) evendia = firsteven.ComputeDiameter(Math.PI / 2); CircularVertex firstodd = odds.FirstOrDefault(); if (firstodd != null) odddia = firstodd.ComputeDiameter(Math.PI / 2); dsa = EllipseAngle(ERadius, Yradius, EStartAngle, ESpacing + (evendia + odddia) / 2) * 180 / Math.PI; break; } case CircularArrangement.ConstantAngle: dsa = ESweepAngle / vertices.Count; break; } // layout evens, then odds if (this.Direction == CircularDirection.BidirectionalLeft) { switch (this.EArrangement) { case CircularArrangement.ConstantDistance: DistanceLayout(evens, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; case CircularArrangement.ConstantSpacing: SpacingLayout(evens, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; case CircularArrangement.ConstantAngle: AngleLayout(evens, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; } switch (this.EArrangement) { case CircularArrangement.ConstantDistance: DistanceLayout(odds, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; case CircularArrangement.ConstantSpacing: SpacingLayout(odds, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; case CircularArrangement.ConstantAngle: AngleLayout(odds, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; } } else { switch (this.EArrangement) { case CircularArrangement.ConstantDistance: DistanceLayout(odds, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; case CircularArrangement.ConstantSpacing: SpacingLayout(odds, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; case CircularArrangement.ConstantAngle: AngleLayout(odds, ESweepAngle / 2, EStartAngle, CircularDirection.Counterclockwise); break; } switch (this.EArrangement) { case CircularArrangement.ConstantDistance: DistanceLayout(evens, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; case CircularArrangement.ConstantSpacing: SpacingLayout(evens, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; case CircularArrangement.ConstantAngle: AngleLayout(evens, ESweepAngle / 2, EStartAngle + dsa, CircularDirection.Clockwise); break; } } } else { // if Direction isn't bidirectional, the nodes are laid out by calling one of these functions. switch (this.EArrangement) { case CircularArrangement.ConstantDistance: DistanceLayout(vertices, ESweepAngle, EStartAngle, Direction); break; case CircularArrangement.ConstantSpacing: SpacingLayout(vertices, ESweepAngle, EStartAngle, Direction); break; case CircularArrangement.ConstantAngle: AngleLayout(vertices, ESweepAngle, EStartAngle, Direction); break; case CircularArrangement.Packed: PackedLayout(vertices, ESweepAngle, EStartAngle, Direction); break; } } // Update the "physical" positions of the nodes and links. if (this.Diagram != null && !this.Diagram.CheckAccess()) { Diagram.InvokeLater(this.Diagram, UpdateParts); } else { UpdateParts(); } this.Network = null; }
/// <summary> /// Allocate a <see cref="CircularNetwork"/>. /// </summary> /// <returns></returns> public virtual CircularNetwork CreateNetwork() { CircularNetwork n = new CircularNetwork(); n.Layout = this; return n; }
private void UpdateParts() { VerifyAccess(); Diagram diagram = this.Diagram; if (diagram != null) diagram.StartTransaction("CircularLayout"); LayoutNodesAndLinks(); if (diagram != null) diagram.CommitTransaction("CircularLayout"); if (diagram != null && diagram.LayoutManager != null) { /* *****/ CircularNetwork net = this.Network; diagram.LayoutManager.AddUpdateLinks(this, () => { this.Network = net; LayoutLinks(); this.Network = null; }); } }