home *** CD-ROM | disk | FTP | other *** search
/ BUG 15 / BUGCD1998_06.ISO / aplic / jbuilder / jsamples.z / Graph.java < prev    next >
Encoding:
Java Source  |  1997-07-30  |  9.8 KB  |  372 lines

  1. // $Header: z:/admin/metro_examples/java/demo/GraphLayout/rcs/Graph.java 1.1 1997/02/06 00:29:58 IPGIntel-2 Exp $ 
  2. /*
  3.  * @(#)Graph.java    1.3 96/12/06
  4.  *
  5.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  6.  *
  7.  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
  8.  * modify and redistribute this software in source and binary code form,
  9.  * provided that i) this copyright notice and license appear on all copies of
  10.  * the software; and ii) Licensee does not utilize the software in a manner
  11.  * which is disparaging to Sun.
  12.  *
  13.  * This software is provided "AS IS," without a warranty of any kind. ALL
  14.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  15.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  16.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  17.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  18.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  19.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  20.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  21.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  22.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  23.  * POSSIBILITY OF SUCH DAMAGES.
  24.  *
  25.  * This software is not designed or intended for use in on-line control of
  26.  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
  27.  * the design, construction, operation or maintenance of any nuclear
  28.  * facility. Licensee represents and warrants that it will not use or
  29.  * redistribute the Software for such purposes.
  30.  */
  31.  
  32. import java.util.*;
  33. import java.awt.*;
  34. import java.applet.Applet;
  35.  
  36. class Node {
  37.     double x;
  38.     double y;
  39.  
  40.     double dx;
  41.     double dy;
  42.  
  43.     boolean fixed;
  44.  
  45.     String lbl;
  46. }
  47.  
  48. class Edge {
  49.     int from;
  50.     int to;
  51.  
  52.     double len;
  53. }
  54.  
  55. class GraphPanel extends Panel implements Runnable {
  56.     Graph graph;
  57.     int nnodes;
  58.     Node nodes[] = new Node[100];
  59.  
  60.     int nedges;
  61.     Edge edges[] = new Edge[200];
  62.  
  63.     Thread relaxer;
  64.     boolean stress;
  65.     boolean random;
  66.  
  67.     GraphPanel(Graph graph) {
  68.     this.graph = graph;
  69.     }
  70.  
  71.     int findNode(String lbl) {
  72.     for (int i = 0 ; i < nnodes ; i++) {
  73.         if (nodes[i].lbl.equals(lbl)) {
  74.         return i;
  75.         }
  76.     }
  77.     return addNode(lbl);
  78.     }
  79.     int addNode(String lbl) {
  80.     Node n = new Node();
  81.     n.x = 10 + 380*Math.random();
  82.     n.y = 10 + 380*Math.random();
  83.     n.lbl = lbl;
  84.     nodes[nnodes] = n;
  85.     return nnodes++;
  86.     }
  87.     void addEdge(String from, String to, int len) {
  88.     Edge e = new Edge();
  89.     e.from = findNode(from);
  90.     e.to = findNode(to);
  91.     e.len = len;
  92.     edges[nedges++] = e;
  93.     }
  94.  
  95.     public void run() {
  96.     while (true) {
  97.         relax();
  98.         if (random && (Math.random() < 0.03)) {
  99.         Node n = nodes[(int)(Math.random() * nnodes)];
  100.         if (!n.fixed) {
  101.             n.x += 100*Math.random() - 50;
  102.             n.y += 100*Math.random() - 50;
  103.         }
  104.         graph.play(graph.getCodeBase(), "audio/drip.au");
  105.         }
  106.         try {
  107.         Thread.sleep(100);
  108.         } catch (InterruptedException e) {
  109.         break;
  110.         }
  111.     }
  112.     }
  113.  
  114.     synchronized void relax() {
  115.     for (int i = 0 ; i < nedges ; i++) {
  116.         Edge e = edges[i];
  117.         double vx = nodes[e.to].x - nodes[e.from].x;
  118.         double vy = nodes[e.to].y - nodes[e.from].y;
  119.         double len = Math.sqrt(vx * vx + vy * vy);
  120.         double f = (edges[i].len - len) / (len * 3) ;
  121.         double dx = f * vx;
  122.         double dy = f * vy;
  123.  
  124.         nodes[e.to].dx += dx;
  125.         nodes[e.to].dy += dy;
  126.         nodes[e.from].dx += -dx;
  127.         nodes[e.from].dy += -dy;
  128.     }
  129.  
  130.     for (int i = 0 ; i < nnodes ; i++) {
  131.         Node n1 = nodes[i];
  132.         double dx = 0;
  133.         double dy = 0;
  134.  
  135.         for (int j = 0 ; j < nnodes ; j++) {
  136.         if (i == j) {
  137.             continue;
  138.         }
  139.         Node n2 = nodes[j];
  140.         double vx = n1.x - n2.x;
  141.         double vy = n1.y - n2.y;
  142.         double len = vx * vx + vy * vy;
  143.         if (len == 0) {
  144.             dx += Math.random();
  145.             dy += Math.random();
  146.         } else if (len < 100*100) {
  147.             dx += vx / len;
  148.             dy += vy / len;
  149.         }
  150.         }
  151.         double dlen = dx * dx + dy * dy;
  152.         if (dlen > 0) {
  153.         dlen = Math.sqrt(dlen) / 2;
  154.         n1.dx += dx / dlen;
  155.         n1.dy += dy / dlen;
  156.         }
  157.     }
  158.  
  159.     Dimension d = size();
  160.     for (int i = 0 ; i < nnodes ; i++) {
  161.         Node n = nodes[i];
  162.         if (!n.fixed) {
  163.         n.x += Math.max(-5, Math.min(5, n.dx));
  164.         n.y += Math.max(-5, Math.min(5, n.dy));
  165.         //System.out.println("v= " + n.dx + "," + n.dy);
  166.         if (n.x < 0) {
  167.             n.x = 0;
  168.         } else if (n.x > d.width) {
  169.             n.x = d.width;
  170.         }
  171.         if (n.y < 0) {
  172.             n.y = 0;
  173.         } else if (n.y > d.height) {
  174.             n.y = d.height;
  175.         }
  176.         }
  177.         n.dx /= 2;
  178.         n.dy /= 2;
  179.     }
  180.     repaint();
  181.     }
  182.  
  183.     Node pick;
  184.     boolean pickfixed;
  185.     Image offscreen;
  186.     Dimension offscreensize;
  187.     Graphics offgraphics;
  188.     
  189.  
  190.     final Color fixedColor = Color.red;
  191.     final Color selectColor = Color.pink;
  192.     final Color edgeColor = Color.black;
  193.     final Color nodeColor = new Color(250, 220, 100);
  194.     final Color stressColor = Color.darkGray;
  195.     final Color arcColor1 = Color.black;
  196.     final Color arcColor2 = Color.pink;
  197.     final Color arcColor3 = Color.red;
  198.  
  199.     public void paintNode(Graphics g, Node n, FontMetrics fm) {
  200.     int x = (int)n.x;
  201.     int y = (int)n.y;
  202.     g.setColor((n == pick) ? selectColor : (n.fixed ? fixedColor : nodeColor));
  203.     int w = fm.stringWidth(n.lbl) + 10;
  204.     int h = fm.getHeight() + 4;
  205.     g.fillRect(x - w/2, y - h / 2, w, h);
  206.     g.setColor(Color.black);
  207.     g.drawRect(x - w/2, y - h / 2, w-1, h-1);
  208.     g.drawString(n.lbl, x - (w-10)/2, (y - (h-4)/2) + fm.getAscent());
  209.     }
  210.  
  211.     public synchronized void update(Graphics g) {
  212.     Dimension d = size();
  213.     if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) {
  214.         offscreen = createImage(d.width, d.height);
  215.         offscreensize = d;
  216.         offgraphics = offscreen.getGraphics();
  217.         offgraphics.setFont(getFont());
  218.     }
  219.  
  220.     offgraphics.setColor(getBackground());
  221.     offgraphics.fillRect(0, 0, d.width, d.height);
  222.     for (int i = 0 ; i < nedges ; i++) {
  223.         Edge e = edges[i];
  224.         int x1 = (int)nodes[e.from].x;
  225.         int y1 = (int)nodes[e.from].y;
  226.         int x2 = (int)nodes[e.to].x;
  227.         int y2 = (int)nodes[e.to].y;
  228.         int len = (int)Math.abs(Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) - e.len);
  229.         offgraphics.setColor((len < 10) ? arcColor1 : (len < 20 ? arcColor2 : arcColor3)) ;
  230.         offgraphics.drawLine(x1, y1, x2, y2);
  231.         if (stress) {
  232.         String lbl = String.valueOf(len);
  233.         offgraphics.setColor(stressColor);
  234.         offgraphics.drawString(lbl, x1 + (x2-x1)/2, y1 + (y2-y1)/2);
  235.         offgraphics.setColor(edgeColor);
  236.         }
  237.     }
  238.  
  239.     FontMetrics fm = offgraphics.getFontMetrics();
  240.     for (int i = 0 ; i < nnodes ; i++) {
  241.         paintNode(offgraphics, nodes[i], fm);
  242.     }
  243.  
  244.     g.drawImage(offscreen, 0, 0, null);
  245.     }
  246.  
  247.     public synchronized boolean mouseDown(Event evt, int x, int y) {
  248.     double bestdist = Double.MAX_VALUE;
  249.     for (int i = 0 ; i < nnodes ; i++) {
  250.         Node n = nodes[i];
  251.         double dist = (n.x - x) * (n.x - x) + (n.y - y) * (n.y - y);
  252.         if (dist < bestdist) {
  253.         pick = n;
  254.         bestdist = dist;
  255.         }
  256.     }
  257.     pickfixed = pick.fixed;
  258.     pick.fixed = true;
  259.     pick.x = x;
  260.     pick.y = y;
  261.     repaint();
  262.     return true;
  263.     }
  264.  
  265.     public synchronized boolean mouseDrag(Event evt, int x, int y) {
  266.     pick.x = x;
  267.     pick.y = y;
  268.     repaint();
  269.     return true;
  270.     }
  271.  
  272.     public synchronized boolean mouseUp(Event evt, int x, int y) {
  273.     pick.x = x;
  274.     pick.y = y;
  275.     pick.fixed = pickfixed;
  276.     pick = null;
  277.     
  278.     repaint();
  279.     return true;
  280.     }
  281.  
  282.     public void start() {
  283.     relaxer = new Thread(this);
  284.     relaxer.start();
  285.     }
  286.     public void stop() {
  287.     relaxer.stop();
  288.     }
  289. }
  290.  
  291. public class Graph extends Applet {
  292.     GraphPanel panel;
  293.  
  294.     public void init() {
  295.     setLayout(new BorderLayout());
  296.  
  297.     panel = new GraphPanel(this);
  298.     add("Center", panel);
  299.     Panel p = new Panel();
  300.     add("South", p);
  301.     p.add(new Button("Scramble"));
  302.     p.add(new Button("Shake"));
  303.     p.add(new Checkbox("Stress"));
  304.     p.add(new Checkbox("Random"));
  305.  
  306.     String edges = getParameter("edges");
  307.     for (StringTokenizer t = new StringTokenizer(edges, ",") ; t.hasMoreTokens() ; ) {
  308.         String str = t.nextToken();
  309.         int i = str.indexOf('-');
  310.         if (i > 0) {
  311.         int len = 50;
  312.         int j = str.indexOf('/');
  313.         if (j > 0) {
  314.             len = Integer.valueOf(str.substring(j+1)).intValue();
  315.             str = str.substring(0, j);
  316.         }
  317.         panel.addEdge(str.substring(0,i), str.substring(i+1), len);
  318.         }
  319.     }
  320.     Dimension d = size();
  321.     String center = getParameter("center");
  322.     if (center != null){
  323.         Node n = panel.nodes[panel.findNode(center)];
  324.         n.x = d.width / 2;
  325.         n.y = d.height / 2;
  326.         n.fixed = true;
  327.     }
  328.     }
  329.  
  330.     public void start() {
  331.     panel.start();
  332.     }
  333.     public void stop() {
  334.     panel.stop();
  335.     }
  336.     public boolean action(Event evt, Object arg) {
  337.     if (arg instanceof Boolean) {
  338.         if (((Checkbox)evt.target).getLabel().equals("Stress")) {
  339.         panel.stress = ((Boolean)arg).booleanValue();
  340.         } else {
  341.         panel.random = ((Boolean)arg).booleanValue();
  342.         }
  343.         return true;
  344.     } 
  345.     if ("Scramble".equals(arg)) {
  346.         play(getCodeBase(), "audio/computer.au");
  347.         Dimension d = size();
  348.         for (int i = 0 ; i < panel.nnodes ; i++) {
  349.         Node n = panel.nodes[i];
  350.         if (!n.fixed) {
  351.             n.x = 10 + (d.width-20)*Math.random();
  352.             n.y = 10 + (d.height-20)*Math.random();
  353.         }
  354.         }
  355.         return true;
  356.     }
  357.     if ("Shake".equals(arg)) {
  358.         play(getCodeBase(), "audio/gong.au");
  359.         Dimension d = size();
  360.         for (int i = 0 ; i < panel.nnodes ; i++) {
  361.         Node n = panel.nodes[i];
  362.         if (!n.fixed) {
  363.             n.x += 80*Math.random() - 40;
  364.             n.y += 80*Math.random() - 40;
  365.         }
  366.         }
  367.         return true;
  368.     }
  369.     return false;
  370.     }
  371. }
  372.