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.layout3d;
12  
13  import java.util.Collection;
14  import java.util.ConcurrentModificationException;
15  import java.util.HashMap;
16  import java.util.HashSet;
17  import java.util.Map;
18  import java.util.Set;
19  
20  import javax.media.j3d.BoundingSphere;
21  import javax.vecmath.Point3f;
22  
23  import org.apache.commons.collections15.Transformer;
24  import org.apache.commons.collections15.map.LazyMap;
25  
26  import edu.uci.ics.jung.graph.Graph;
27  
28  /**
29   * Implements some of the dirty work of writing a layout algorithm, allowing
30   * the user to express their major intent more simply. When writing a <tt>Layout</tt>,
31   * there are many shared tasks: handling tracking locked nodes, applying
32   * filters, and tracing nearby vertices. This package automates all of those.
33   * 
34   * @author Danyel Fisher, Scott White
35   * @param <V>
36   */
37  public abstract class AbstractLayout<V, E> implements Layout<V,E> {
38  
39      /**
40       * a set of vertices that should not move in relation to the
41       * other vertices
42       */
43  	private Set<V> dontmove = new HashSet<V>();
44  
45  	private BoundingSphere size;
46  	private Graph<V, E> graph;
47      
48      protected Map<V, Point3f> locations = 
49      	LazyMap.decorate(new HashMap<V, Point3f>(),
50      			new Transformer<V,Point3f>() {
51  					public Point3f transform(V arg0) {
52  						return new Point3f();
53  					}});
54  
55  
56  	/**
57  	 * Constructor. Initializes the current size to be 100x100, both the graph
58  	 * and the showing graph to the argument, and creates the <tt>dontmove</tt>
59  	 * set.
60  	 * 
61  	 * @param g
62  	 */
63  	protected AbstractLayout(Graph<V, E> graph) {
64  		this.graph = graph;
65  	}
66  	
67  	protected AbstractLayout(Graph<V,E> graph, Transformer<V,Point3f> initializer) {
68  		this.graph = graph;
69  		this.locations = LazyMap.decorate(new HashMap<V,Point3f>(), initializer);
70  	}
71  	
72  	protected AbstractLayout(Graph<V,E> graph, BoundingSphere size) {
73  		this.graph = graph;
74  		this.size = size;
75  	}
76  	
77  	protected AbstractLayout(Graph<V,E> graph, Transformer<V,Point3f> initializer, BoundingSphere size) {
78  		this.graph = graph;
79  		this.locations = LazyMap.decorate(new HashMap<V,Point3f>(), initializer);
80  		this.size = size;
81  	}
82      
83      public void setGraph(Graph<V,E> graph) {
84          this.graph = graph;
85          if(size != null && graph != null) {
86          	initialize();
87          }
88      }
89      
90  	/**
91  	 * When a visualization is resized, it presumably wants to fix the
92  	 * locations of the vertices and possibly to reinitialize its data. The
93  	 * current method calls <tt>initializeLocations</tt> followed by <tt>initialize_local</tt>.
94  	 * TODO: A better implementation wouldn't destroy the current information,
95  	 * but would either scale the current visualization, or move the nodes
96  	 * toward the new center.
97  	 */
98  	public void setSize(BoundingSphere size) {
99  		
100 		if(size != null && graph != null) {
101 			
102 			BoundingSphere oldSize = this.size;
103 			this.size = size;
104 			initialize();
105 			
106 			if(oldSize != null) {
107 				adjustLocations(oldSize, size);
108 			}
109 		}
110 	}
111 	
112 	private void adjustLocations(BoundingSphere oldSize, BoundingSphere size) {
113 		
114 		float oldWidth = 0;
115 		float oldHeight = 0;
116 		float oldDepth = 0;
117 		float width = 0;
118 		float height = 0;
119 		float depth = 0;
120 		
121 		oldWidth = oldHeight = oldDepth = (float) (2*oldSize.getRadius());
122 		width = height = depth = (float) (2*size.getRadius());
123 
124 		float xOffset = (oldWidth - width) / 2;
125 		float yOffset = (oldHeight - height) / 2;
126 		float zOffset = (oldDepth - depth) / 2;
127 
128 		// now, move each vertex to be at the new screen center
129 		while(true) {
130 		    try {
131                 for(V v : getGraph().getVertices()) {
132 		            offsetVertex(v, xOffset, yOffset, zOffset);
133 		        }
134 		        break;
135 		    } catch(ConcurrentModificationException cme) {
136 		    }
137 		}
138 	}
139     
140     public boolean isLocked(V v) {
141         return dontmove.contains(v);
142     }
143 
144     public Collection<V> getVertices() {
145     	return getGraph().getVertices();
146     }
147     
148 	/**
149 	 * Initializer, calls <tt>intialize_local</tt> and <tt>initializeLocations</tt>
150 	 * to start construction process.
151 	 */
152 	public abstract void initialize();
153 
154     public void setInitializer(Transformer<V,Point3f> initializer) {
155     	this.locations = LazyMap.decorate(new HashMap<V,Point3f>(locations), initializer);
156     }
157     
158 	/**
159 	 * Returns the current size of the visualization space, accoring to the
160 	 * last call to resize().
161 	 * 
162 	 * @return the current size of the screen
163 	 */
164 	public BoundingSphere getSize() {
165 		return size;
166 	}
167 
168 	/**
169 	 * Returns the Coordinates object that stores the vertex' x and y location.
170 	 * 
171 	 * @param v
172 	 *            A Vertex that is a part of the Graph being visualized.
173 	 * @return A Coordinates object with x and y locations.
174 	 */
175 	private Point3f getCoordinates(V v) {
176         return locations.get(v);
177 	}
178 	
179 	public Point3f transform(V v) {
180 		return getCoordinates(v);
181 	}
182 	
183 	/**
184 	 * Returns the x coordinate of the vertex from the Coordinates object.
185 	 * in most cases you will be better off calling getLocation(Vertex v);
186 	 * @see edu.uci.ics.jung.visualization.layout.Layout#getX(edu.uci.ics.jung.graph.Vertex)
187 	 */
188 	public double getX(V v) {
189         assert getCoordinates(v) != null : "Cannot getX for an unmapped vertex "+v;
190         return getCoordinates(v).getX();
191 	}
192 
193 	/**
194 	 * Returns the y coordinate of the vertex from the Coordinates object.
195 	 * In most cases you will be better off calling getLocation(Vertex v)
196 	 * @see edu.uci.ics.jung.visualization.layout.Layout#getX(edu.uci.ics.jung.graph.Vertex)
197 	 */
198 	public double getY(V v) {
199         assert getCoordinates(v) != null : "Cannot getY for an unmapped vertex "+v;
200         return getCoordinates(v).getY();
201 	}
202 	
203     /**
204      * @param v a Vertex of interest
205      * @return the location point of the supplied vertex
206      */
207 //	public Point3f getLocation(V v) {
208 //	    return getCoordinates(v);
209 //	}
210 
211 	/**
212 	 * @param v
213 	 * @param xOffset
214 	 * @param yOffset
215 	 */
216 	protected void offsetVertex(V v, float xOffset, float yOffset, float zOffset) {
217 		Point3f c = getCoordinates(v);
218         c.set(c.getX()+xOffset, c.getY()+yOffset, c.getZ()+zOffset);
219 		setLocation(v, c);
220 	}
221 
222 	/**
223 	 * Accessor for the graph that represets all vertices.
224 	 * 
225 	 * @return the graph that contains all vertices.
226 	 */
227 	public Graph<V, E> getGraph() {
228 	    return graph;
229 	}
230 	
231 	/**
232 	 * Forcibly moves a vertex to the (x,y) location by setting its x and y
233 	 * locations to the inputted location. Does not add the vertex to the
234 	 * "dontmove" list, and (in the default implementation) does not make any
235 	 * adjustments to the rest of the graph.
236 	 */
237 	public void setLocation(V picked, float x, float y, float z) {
238 		Point3f coord = getCoordinates(picked);
239 		coord.set(x, y, z);
240 	}
241 
242 	public void setLocation(V picked, Point3f p) {
243 		Point3f coord = getCoordinates(picked);
244 		coord.set(p);
245 	}
246 
247 	/**
248 	 * Adds the vertex to the DontMove list
249 	 */
250 	public void lock(V v, boolean state) {
251 		if(state == true) dontmove.add(v);
252 		else dontmove.remove(v);
253 	}
254 	
255 	public void lock(boolean lock) {
256 		for(V v : graph.getVertices()) {
257 			lock(v, lock);
258 		}
259 	}
260 }