View Javadoc

1   /*
2    * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3    * California All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or http://jung.sourceforge.net/license.txt for a description.
7    * 
8    * Created on Jul 7, 2003
9    * 
10   */
11  package edu.uci.ics.jung.algorithms.layout;
12  
13  import java.awt.Dimension;
14  import java.awt.geom.Point2D;
15  import java.util.ConcurrentModificationException;
16  import java.util.HashMap;
17  import java.util.HashSet;
18  import java.util.Map;
19  import java.util.Set;
20  
21  import org.apache.commons.collections15.Transformer;
22  import org.apache.commons.collections15.functors.ChainedTransformer;
23  import org.apache.commons.collections15.functors.CloneTransformer;
24  import org.apache.commons.collections15.map.LazyMap;
25  
26  import edu.uci.ics.jung.graph.Graph;
27  
28  /**
29   * Abstract class for implementations of {@code Layout}.  It handles some of the
30   * basic functions: storing coordinates, maintaining the dimensions, initializing
31   * the locations, maintaining locked vertices.
32   * 
33   * @author Danyel Fisher, Scott White
34   * @author Tom Nelson - converted to jung2
35   * @param <V> the vertex type
36   * @param <E> the edge type
37   */
38  abstract public class AbstractLayout<V, E> implements Layout<V,E> {
39  
40      /**
41       * a set of vertices that should not move in relation to the
42       * other vertices
43       */
44  	private Set<V> dontmove = new HashSet<V>();
45  
46  	protected Dimension size;
47  	protected Graph<V, E> graph;
48  	protected boolean initialized;
49      
50      protected Map<V, Point2D> locations = 
51      	LazyMap.decorate(new HashMap<V, Point2D>(),
52      			new Transformer<V,Point2D>() {
53  					public Point2D transform(V arg0) {
54  						return new Point2D.Double();
55  					}});
56  
57  
58  	/**
59  	 * Creates an instance which does not initialize the vertex locations.
60  	 * 
61  	 * @param graph the graph for which the layout algorithm is to be created.
62  	 */
63  	protected AbstractLayout(Graph<V, E> graph) {
64  	    if (graph == null) 
65  	    {
66  	        throw new IllegalArgumentException("Graph must be non-null");
67  	    }
68  		this.graph = graph;
69  	}
70  	
71      @SuppressWarnings("unchecked")
72      protected AbstractLayout(Graph<V,E> graph, Transformer<V,Point2D> initializer) {
73  		this.graph = graph;
74  		Transformer<V, ? extends Object> chain = 
75  			ChainedTransformer.getInstance(initializer, CloneTransformer.getInstance());
76  		this.locations = LazyMap.decorate(new HashMap<V,Point2D>(), (Transformer<V,Point2D>)chain);
77  		initialized = true;
78  	}
79  	
80  	protected AbstractLayout(Graph<V,E> graph, Dimension size) {
81  		this.graph = graph;
82  		this.size = size;
83  	}
84  	
85  	@SuppressWarnings("unchecked")
86      protected AbstractLayout(Graph<V,E> graph, Transformer<V,Point2D> initializer, Dimension size) {
87  		this.graph = graph;
88  		Transformer<V, ? extends Object> chain = 
89  			ChainedTransformer.getInstance(initializer, CloneTransformer.getInstance());
90  		this.locations = LazyMap.decorate(new HashMap<V,Point2D>(), (Transformer<V,Point2D>)chain);
91  		this.size = size;
92  	}
93      
94      public void setGraph(Graph<V,E> graph) {
95          this.graph = graph;
96          if(size != null && graph != null) {
97          	initialize();
98          }
99      }
100     
101 	/**
102 	 * When a visualization is resized, it presumably wants to fix the
103 	 * locations of the vertices and possibly to reinitialize its data. The
104 	 * current method calls <tt>initializeLocations</tt> followed by <tt>initialize_local</tt>.
105 	 */
106 	public void setSize(Dimension size) {
107 		
108 		if(size != null && graph != null) {
109 			
110 			Dimension oldSize = this.size;
111 			this.size = size;
112 			initialize();
113 			
114 			if(oldSize != null) {
115 				adjustLocations(oldSize, size);
116 			}
117 		}
118 	}
119 	
120 	private void adjustLocations(Dimension oldSize, Dimension size) {
121 
122 		int xOffset = (size.width - oldSize.width) / 2;
123 		int yOffset = (size.height - oldSize.height) / 2;
124 
125 		// now, move each vertex to be at the new screen center
126 		while(true) {
127 		    try {
128                 for(V v : getGraph().getVertices()) {
129 		            offsetVertex(v, xOffset, yOffset);
130 		        }
131 		        break;
132 		    } catch(ConcurrentModificationException cme) {
133 		    }
134 		}
135 	}
136     
137     public boolean isLocked(V v) {
138         return dontmove.contains(v);
139     }
140     
141     @SuppressWarnings("unchecked")
142     public void setInitializer(Transformer<V,Point2D> initializer) {
143     	if(this.equals(initializer)) {
144     		throw new IllegalArgumentException("Layout cannot be initialized with itself");
145     	}
146 		Transformer<V, ? extends Object> chain = 
147 			ChainedTransformer.getInstance(initializer, CloneTransformer.getInstance());
148     	this.locations = LazyMap.decorate(new HashMap<V,Point2D>(), (Transformer<V, Point2D>)chain);
149     	initialized = true;
150     }
151     
152 	/**
153 	 * Returns the current size of the visualization space, accoring to the
154 	 * last call to resize().
155 	 * 
156 	 * @return the current size of the screen
157 	 */
158 	public Dimension getSize() {
159 		return size;
160 	}
161 
162 	/**
163 	 * Returns the Coordinates object that stores the vertex' x and y location.
164 	 * 
165 	 * @param v
166 	 *            A Vertex that is a part of the Graph being visualized.
167 	 * @return A Coordinates object with x and y locations.
168 	 */
169 	private Point2D getCoordinates(V v) {
170         return locations.get(v);
171 	}
172 	
173 	public Point2D transform(V v) {
174 		return getCoordinates(v);
175 	}
176 	
177 	/**
178 	 * Returns the x coordinate of the vertex from the Coordinates object.
179 	 * in most cases you will be better off calling transform(v).
180 	 */
181 	public double getX(V v) {
182         assert getCoordinates(v) != null : "Cannot getX for an unmapped vertex "+v;
183         return getCoordinates(v).getX();
184 	}
185 
186 	/**
187 	 * Returns the y coordinate of the vertex from the Coordinates object.
188 	 * In most cases you will be better off calling transform(v).
189 	 */
190 	public double getY(V v) {
191         assert getCoordinates(v) != null : "Cannot getY for an unmapped vertex "+v;
192         return getCoordinates(v).getY();
193 	}
194 	
195 	/**
196 	 * @param v
197 	 * @param xOffset
198 	 * @param yOffset
199 	 */
200 	protected void offsetVertex(V v, double xOffset, double yOffset) {
201 		Point2D c = getCoordinates(v);
202         c.setLocation(c.getX()+xOffset, c.getY()+yOffset);
203 		setLocation(v, c);
204 	}
205 
206 	/**
207 	 * Accessor for the graph that represets all vertices.
208 	 * 
209 	 * @return the graph that contains all vertices.
210 	 */
211 	public Graph<V, E> getGraph() {
212 	    return graph;
213 	}
214 	
215 	/**
216 	 * Forcibly moves a vertex to the (x,y) location by setting its x and y
217 	 * locations to the inputted location. Does not add the vertex to the
218 	 * "dontmove" list, and (in the default implementation) does not make any
219 	 * adjustments to the rest of the graph.
220 	 */
221 	public void setLocation(V picked, double x, double y) {
222 		Point2D coord = getCoordinates(picked);
223 		coord.setLocation(x, y);
224 	}
225 
226 	public void setLocation(V picked, Point2D p) {
227 		Point2D coord = getCoordinates(picked);
228 		coord.setLocation(p);
229 	}
230 
231 	/**
232 	 * Locks {@code v} in place if {@code state} is {@code true}, otherwise unlocks it.
233 	 */
234 	public void lock(V v, boolean state) {
235 		if(state == true) 
236 		    dontmove.add(v);
237 		else 
238 		    dontmove.remove(v);
239 	}
240 	
241 	/**
242 	 * Locks all vertices in place if {@code lock} is {@code true}, otherwise unlocks all vertices.
243 	 */
244 	public void lock(boolean lock) {
245 		for(V v : graph.getVertices()) {
246 			lock(v, lock);
247 		}
248 	}
249 }