KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > Graph


1 /*
2  * @(#)Graph.java 1.18 06/02/22
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 /*
38  * @(#)Graph.java 1.18 06/02/22
39  */

40
41 import java.util.*;
42 import java.awt.*;
43 import java.applet.Applet JavaDoc;
44 import java.awt.event.*;
45
46
47 class Node {
48     double x;
49     double y;
50
51     double dx;
52     double dy;
53
54     boolean fixed;
55
56     String JavaDoc lbl;
57 }
58
59
60 class Edge {
61     int from;
62     int to;
63
64     double len;
65 }
66
67
68 class GraphPanel extends Panel
69     implements Runnable JavaDoc, MouseListener, MouseMotionListener {
70     Graph graph;
71     int nnodes;
72     Node nodes[] = new Node[100];
73
74     int nedges;
75     Edge edges[] = new Edge[200];
76
77     Thread JavaDoc relaxer;
78     boolean stress;
79     boolean random;
80
81     int numMouseButtonsDown = 0;
82
83     GraphPanel(Graph graph) {
84     this.graph = graph;
85     addMouseListener(this);
86     }
87
88     int findNode(String JavaDoc lbl) {
89     for (int i = 0 ; i < nnodes ; i++) {
90         if (nodes[i].lbl.equals(lbl)) {
91         return i;
92         }
93     }
94     return addNode(lbl);
95     }
96     int addNode(String JavaDoc lbl) {
97     Node n = new Node();
98     n.x = 10 + 380*Math.random();
99     n.y = 10 + 380*Math.random();
100     n.lbl = lbl;
101     nodes[nnodes] = n;
102     return nnodes++;
103     }
104     void addEdge(String JavaDoc from, String JavaDoc to, int len) {
105     Edge e = new Edge();
106     e.from = findNode(from);
107     e.to = findNode(to);
108     e.len = len;
109     edges[nedges++] = e;
110     }
111
112     public void run() {
113         Thread JavaDoc me = Thread.currentThread();
114     while (relaxer == me) {
115         relax();
116         if (random && (Math.random() < 0.03)) {
117         Node n = nodes[(int)(Math.random() * nnodes)];
118         if (!n.fixed) {
119             n.x += 100*Math.random() - 50;
120             n.y += 100*Math.random() - 50;
121         }
122         graph.play(graph.getCodeBase(), "audio/drip.au");
123         }
124         try {
125         Thread.sleep(100);
126         } catch (InterruptedException JavaDoc e) {
127         break;
128         }
129     }
130     }
131
132     synchronized void relax() {
133     for (int i = 0 ; i < nedges ; i++) {
134         Edge e = edges[i];
135         double vx = nodes[e.to].x - nodes[e.from].x;
136         double vy = nodes[e.to].y - nodes[e.from].y;
137         double len = Math.sqrt(vx * vx + vy * vy);
138             len = (len == 0) ? .0001 : len;
139         double f = (edges[i].len - len) / (len * 3);
140         double dx = f * vx;
141         double dy = f * vy;
142
143         nodes[e.to].dx += dx;
144         nodes[e.to].dy += dy;
145         nodes[e.from].dx += -dx;
146         nodes[e.from].dy += -dy;
147     }
148
149     for (int i = 0 ; i < nnodes ; i++) {
150         Node n1 = nodes[i];
151         double dx = 0;
152         double dy = 0;
153
154         for (int j = 0 ; j < nnodes ; j++) {
155         if (i == j) {
156             continue;
157         }
158         Node n2 = nodes[j];
159         double vx = n1.x - n2.x;
160         double vy = n1.y - n2.y;
161         double len = vx * vx + vy * vy;
162         if (len == 0) {
163             dx += Math.random();
164             dy += Math.random();
165         } else if (len < 100*100) {
166             dx += vx / len;
167             dy += vy / len;
168         }
169         }
170         double dlen = dx * dx + dy * dy;
171         if (dlen > 0) {
172         dlen = Math.sqrt(dlen) / 2;
173         n1.dx += dx / dlen;
174         n1.dy += dy / dlen;
175         }
176     }
177
178     Dimension d = getSize();
179     for (int i = 0 ; i < nnodes ; i++) {
180         Node n = nodes[i];
181         if (!n.fixed) {
182         n.x += Math.max(-5, Math.min(5, n.dx));
183         n.y += Math.max(-5, Math.min(5, n.dy));
184             }
185             if (n.x < 0) {
186                 n.x = 0;
187             } else if (n.x > d.width) {
188                 n.x = d.width;
189             }
190             if (n.y < 0) {
191                 n.y = 0;
192             } else if (n.y > d.height) {
193                 n.y = d.height;
194             }
195         n.dx /= 2;
196         n.dy /= 2;
197     }
198     repaint();
199     }
200
201     Node pick;
202     boolean pickfixed;
203     Image offscreen;
204     Dimension offscreensize;
205     Graphics offgraphics;
206
207     final Color fixedColor = Color.red;
208     final Color selectColor = Color.pink;
209     final Color edgeColor = Color.black;
210     final Color nodeColor = new Color(250, 220, 100);
211     final Color stressColor = Color.darkGray;
212     final Color arcColor1 = Color.black;
213     final Color arcColor2 = Color.pink;
214     final Color arcColor3 = Color.red;
215
216     public void paintNode(Graphics g, Node n, FontMetrics fm) {
217     int x = (int)n.x;
218     int y = (int)n.y;
219     g.setColor((n == pick) ? selectColor : (n.fixed ? fixedColor : nodeColor));
220     int w = fm.stringWidth(n.lbl) + 10;
221     int h = fm.getHeight() + 4;
222     g.fillRect(x - w/2, y - h / 2, w, h);
223     g.setColor(Color.black);
224     g.drawRect(x - w/2, y - h / 2, w-1, h-1);
225     g.drawString(n.lbl, x - (w-10)/2, (y - (h-4)/2) + fm.getAscent());
226     }
227
228     public synchronized void update(Graphics g) {
229     Dimension d = getSize();
230     if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) {
231         offscreen = createImage(d.width, d.height);
232         offscreensize = d;
233         if (offgraphics != null) {
234             offgraphics.dispose();
235         }
236         offgraphics = offscreen.getGraphics();
237         offgraphics.setFont(getFont());
238     }
239
240     offgraphics.setColor(getBackground());
241     offgraphics.fillRect(0, 0, d.width, d.height);
242     for (int i = 0 ; i < nedges ; i++) {
243         Edge e = edges[i];
244         int x1 = (int)nodes[e.from].x;
245         int y1 = (int)nodes[e.from].y;
246         int x2 = (int)nodes[e.to].x;
247         int y2 = (int)nodes[e.to].y;
248         int len = (int)Math.abs(Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) - e.len);
249         offgraphics.setColor((len < 10) ? arcColor1 : (len < 20 ? arcColor2 : arcColor3)) ;
250         offgraphics.drawLine(x1, y1, x2, y2);
251         if (stress) {
252         String JavaDoc lbl = String.valueOf(len);
253         offgraphics.setColor(stressColor);
254         offgraphics.drawString(lbl, x1 + (x2-x1)/2, y1 + (y2-y1)/2);
255         offgraphics.setColor(edgeColor);
256         }
257     }
258
259     FontMetrics fm = offgraphics.getFontMetrics();
260     for (int i = 0 ; i < nnodes ; i++) {
261         paintNode(offgraphics, nodes[i], fm);
262     }
263     g.drawImage(offscreen, 0, 0, null);
264     }
265
266     //1.1 event handling
267
public void mouseClicked(MouseEvent e) {
268     }
269
270     public void mousePressed(MouseEvent e) {
271         numMouseButtonsDown++;
272         addMouseMotionListener(this);
273     double bestdist = Double.MAX_VALUE;
274
275     int x = e.getX();
276     int y = e.getY();
277     for (int i = 0 ; i < nnodes ; i++) {
278         Node n = nodes[i];
279         double dist = (n.x - x) * (n.x - x) + (n.y - y) * (n.y - y);
280         if (dist < bestdist) {
281         pick = n;
282         bestdist = dist;
283         }
284     }
285     pickfixed = pick.fixed;
286     pick.fixed = true;
287     pick.x = x;
288     pick.y = y;
289
290     repaint();
291     e.consume();
292     }
293
294     public void mouseReleased(MouseEvent e) {
295         numMouseButtonsDown--;
296         removeMouseMotionListener(this);
297
298         pick.fixed = pickfixed;
299         pick.x = e.getX();
300         pick.y = e.getY();
301         if (numMouseButtonsDown == 0) {
302             pick = null;
303         }
304
305         repaint();
306         e.consume();
307     }
308
309     public void mouseEntered(MouseEvent e) {
310     }
311
312     public void mouseExited(MouseEvent e) {
313     }
314
315     public void mouseDragged(MouseEvent e) {
316     pick.x = e.getX();
317     pick.y = e.getY();
318     repaint();
319     e.consume();
320     }
321
322     public void mouseMoved(MouseEvent e) {
323     }
324
325     public void start() {
326     relaxer = new Thread JavaDoc(this);
327     relaxer.start();
328     }
329
330     public void stop() {
331     relaxer = null;
332     }
333
334 }
335
336
337 public class Graph extends Applet JavaDoc implements ActionListener, ItemListener {
338
339     GraphPanel panel;
340     Panel controlPanel;
341
342     Button scramble = new Button("Scramble");
343     Button shake = new Button("Shake");
344     Checkbox stress = new Checkbox("Stress");
345     Checkbox random = new Checkbox("Random");
346
347     public void init() {
348     setLayout(new BorderLayout());
349
350     panel = new GraphPanel(this);
351     add("Center", panel);
352     controlPanel = new Panel();
353     add("South", controlPanel);
354
355     controlPanel.add(scramble); scramble.addActionListener(this);
356     controlPanel.add(shake); shake.addActionListener(this);
357     controlPanel.add(stress); stress.addItemListener(this);
358     controlPanel.add(random); random.addItemListener(this);
359
360     String JavaDoc edges = getParameter("edges");
361     for (StringTokenizer t = new StringTokenizer(edges, ",") ; t.hasMoreTokens() ; ) {
362         String JavaDoc str = t.nextToken();
363         int i = str.indexOf('-');
364         if (i > 0) {
365         int len = 50;
366         int j = str.indexOf('/');
367         if (j > 0) {
368             len = Integer.valueOf(str.substring(j+1)).intValue();
369             str = str.substring(0, j);
370         }
371         panel.addEdge(str.substring(0,i), str.substring(i+1), len);
372         }
373     }
374     Dimension d = getSize();
375     String JavaDoc center = getParameter("center");
376     if (center != null){
377         Node n = panel.nodes[panel.findNode(center)];
378         n.x = d.width / 2;
379         n.y = d.height / 2;
380         n.fixed = true;
381     }
382     }
383
384     public void destroy() {
385         remove(panel);
386         remove(controlPanel);
387     }
388
389     public void start() {
390     panel.start();
391     }
392
393     public void stop() {
394     panel.stop();
395     }
396
397     public void actionPerformed(ActionEvent e) {
398     Object JavaDoc src = e.getSource();
399
400     if (src == scramble) {
401         play(getCodeBase(), "audio/computer.au");
402         Dimension d = getSize();
403         for (int i = 0 ; i < panel.nnodes ; i++) {
404         Node n = panel.nodes[i];
405         if (!n.fixed) {
406             n.x = 10 + (d.width-20)*Math.random();
407             n.y = 10 + (d.height-20)*Math.random();
408         }
409         }
410         return;
411     }
412
413     if (src == shake) {
414         play(getCodeBase(), "audio/gong.au");
415         Dimension d = getSize();
416         for (int i = 0 ; i < panel.nnodes ; i++) {
417         Node n = panel.nodes[i];
418         if (!n.fixed) {
419             n.x += 80*Math.random() - 40;
420             n.y += 80*Math.random() - 40;
421         }
422         }
423     }
424
425     }
426
427     public void itemStateChanged(ItemEvent e) {
428     Object JavaDoc src = e.getSource();
429     boolean on = e.getStateChange() == ItemEvent.SELECTED;
430     if (src == stress) panel.stress = on;
431     else if (src == random) panel.random = on;
432     }
433
434     public String JavaDoc getAppletInfo() {
435     return "Title: GraphLayout \nAuthor: <unknown>";
436     }
437
438     public String JavaDoc[][] getParameterInfo() {
439     String JavaDoc[][] info = {
440         {"edges", "delimited string", "A comma-delimited list of all the edges. It takes the form of 'C-N1,C-N2,C-N3,C-NX,N1-N2/M12,N2-N3/M23,N3-NX/M3X,...' where C is the name of center node (see 'center' parameter) and NX is a node attached to the center node. For the edges connecting nodes to each other (and not to the center node) you may (optionally) specify a length MXY separated from the edge name by a forward slash."},
441         {"center", "string", "The name of the center node."}
442     };
443     return info;
444     }
445
446 }
447
Popular Tags