View Javadoc
1   /*
2    * Copyright (c) 2003, The JUNG Authors 
3    *
4    * All rights reserved.
5    *
6    * This software is open-source under the BSD license; see either
7    * "license.txt" or
8    * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9    */
10  /*
11   * Created on Dec 4, 2003
12   */
13  package edu.uci.ics.jung.algorithms.layout;
14  
15  import java.awt.Dimension;
16  import java.awt.geom.Point2D;
17  import java.util.ArrayList;
18  import java.util.Collections;
19  import java.util.Comparator;
20  import java.util.List;
21  
22  import com.google.common.cache.CacheBuilder;
23  import com.google.common.cache.CacheLoader;
24  import com.google.common.cache.LoadingCache;
25  
26  import edu.uci.ics.jung.graph.Graph;
27  
28  
29  
30  /**
31   * A {@code Layout} implementation that positions vertices equally spaced on a regular circle.
32   *
33   * @author Masanori Harada
34   */
35  public class CircleLayout<V, E> extends AbstractLayout<V,E> {
36  
37  	private double radius;
38  	private List<V> vertex_ordered_list;
39  	
40      protected LoadingCache<V, CircleVertexData> circleVertexDatas =
41      	CacheBuilder.newBuilder().build(new CacheLoader<V, CircleVertexData>() {
42  	    	public CircleVertexData load(V vertex) {
43  	    		return new CircleVertexData();
44  	    	}
45      });
46  
47  	public CircleLayout(Graph<V,E> g) {
48  		super(g);
49  	}
50  
51  	/**
52  	 * @return the radius of the circle.
53  	 */
54  	public double getRadius() {
55  		return radius;
56  	}
57  
58  	/**
59  	 * Sets the radius of the circle.  Must be called before {@code initialize()} is called.
60  	 * @param radius the radius of the circle
61  	 */
62  	public void setRadius(double radius) {
63  		this.radius = radius;
64  	}
65  
66  	/**
67  	 * Sets the order of the vertices in the layout according to the ordering
68  	 * specified by {@code comparator}.
69  	 * @param comparator the comparator to use to order the vertices
70  	 */
71  	public void setVertexOrder(Comparator<V> comparator)
72  	{
73  	    if (vertex_ordered_list == null)
74  	        vertex_ordered_list = new ArrayList<V>(getGraph().getVertices());
75  	    Collections.sort(vertex_ordered_list, comparator);
76  	}
77  
78      /**
79       * Sets the order of the vertices in the layout according to the ordering
80       * of {@code vertex_list}.
81       * @param vertex_list a list specifying the ordering of the vertices
82       */
83  	public void setVertexOrder(List<V> vertex_list)
84  	{
85  	    if (!vertex_list.containsAll(getGraph().getVertices())) 
86  	        throw new IllegalArgumentException("Supplied list must include " +
87  	        		"all vertices of the graph");
88  	    this.vertex_ordered_list = vertex_list;
89  	}
90  	
91  	public void reset() {
92  		initialize();
93  	}
94  
95  	public void initialize() 
96  	{
97  		Dimension d = getSize();
98  		
99  		if (d != null) 
100 		{
101 		    if (vertex_ordered_list == null) 
102 		        setVertexOrder(new ArrayList<V>(getGraph().getVertices()));
103 
104 			double height = d.getHeight();
105 			double width = d.getWidth();
106 
107 			if (radius <= 0) {
108 				radius = 0.45 * (height < width ? height : width);
109 			}
110 
111 			int i = 0;
112 			for (V v : vertex_ordered_list)
113 			{
114 				Point2D coord = apply(v);
115 
116 				double angle = (2 * Math.PI * i) / vertex_ordered_list.size();
117 
118 				coord.setLocation(Math.cos(angle) * radius + width / 2,
119 						Math.sin(angle) * radius + height / 2);
120 
121 				CircleVertexData data = getCircleData(v);
122 				data.setAngle(angle);
123 				i++;
124 			}
125 		}
126 	}
127 
128 	protected CircleVertexData getCircleData(V v) {
129 		return circleVertexDatas.getUnchecked(v);
130 	}
131 
132 	protected static class CircleVertexData {
133 		private double angle;
134 
135 		protected double getAngle() {
136 			return angle;
137 		}
138 
139 		protected void setAngle(double angle) {
140 			this.angle = angle;
141 		}
142 
143 		@Override
144 		public String toString() {
145 			return "CircleVertexData: angle=" + angle;
146 		}
147 	}
148 }