home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 December / PCWKCD1296.iso / vjplusb / msdev / samples / sun / graphlayout / graph.java < prev    next >
Text File  |  1996-07-10  |  8KB  |  342 lines

  1.  
  2. import java.util.*;
  3. import java.awt.*;
  4. import java.applet.Applet;
  5.  
  6. class Node {
  7.     double x;
  8.     double y;
  9.  
  10.     double dx;
  11.     double dy;
  12.  
  13.     boolean fixed;
  14.  
  15.     String lbl;
  16. }
  17.  
  18. class Edge {
  19.     int from;
  20.     int to;
  21.  
  22.     double len;
  23. }
  24.  
  25. class GraphPanel extends Panel implements Runnable {
  26.     graph graphObj;
  27.     int nnodes;
  28.     Node nodes[] = new Node[100];
  29.  
  30.     int nedges;
  31.     Edge edges[] = new Edge[200];
  32.  
  33.     Thread relaxer;
  34.     boolean stress;
  35.     boolean random;
  36.  
  37.     GraphPanel(graph graphObj) {
  38.     this.graphObj = graphObj;
  39.     }
  40.  
  41.     int findNode(String lbl) {
  42.     for (int i = 0 ; i < nnodes ; i++) {
  43.         if (nodes[i].lbl.equals(lbl)) {
  44.         return i;
  45.         }
  46.     }
  47.     return addNode(lbl);
  48.     }
  49.     int addNode(String lbl) {
  50.     Node n = new Node();
  51.     n.x = 10 + 380*Math.random();
  52.     n.y = 10 + 380*Math.random();
  53.     n.lbl = lbl;
  54.     nodes[nnodes] = n;
  55.     return nnodes++;
  56.     }
  57.     void addEdge(String from, String to, int len) {
  58.     Edge e = new Edge();
  59.     e.from = findNode(from);
  60.     e.to = findNode(to);
  61.     e.len = len;
  62.     edges[nedges++] = e;
  63.     }
  64.  
  65.     public void run() {
  66.     while (true) {
  67.         relax();
  68.         if (random && (Math.random() < 0.03)) {
  69.         Node n = nodes[(int)(Math.random() * nnodes)];
  70.         if (!n.fixed) {
  71.             n.x += 100*Math.random() - 50;
  72.             n.y += 100*Math.random() - 50;
  73.         }
  74.         graphObj.play(graphObj.getCodeBase(), "audio/drip.au");
  75.         }
  76.         try {
  77.         Thread.sleep(100);
  78.         } catch (InterruptedException e) {
  79.         break;
  80.         }
  81.     }
  82.     }
  83.  
  84.     synchronized void relax() {
  85.     for (int i = 0 ; i < nedges ; i++) {
  86.         Edge e = edges[i];
  87.         double vx = nodes[e.to].x - nodes[e.from].x;
  88.         double vy = nodes[e.to].y - nodes[e.from].y;
  89.         double len = Math.sqrt(vx * vx + vy * vy);
  90.         double f = (edges[i].len - len) / (len * 3) ;
  91.         double dx = f * vx;
  92.         double dy = f * vy;
  93.  
  94.         nodes[e.to].dx += dx;
  95.         nodes[e.to].dy += dy;
  96.         nodes[e.from].dx += -dx;
  97.         nodes[e.from].dy += -dy;
  98.     }
  99.  
  100.     for (int i = 0 ; i < nnodes ; i++) {
  101.         Node n1 = nodes[i];
  102.         double dx = 0;
  103.         double dy = 0;
  104.  
  105.         for (int j = 0 ; j < nnodes ; j++) {
  106.         if (i == j) {
  107.             continue;
  108.         }
  109.         Node n2 = nodes[j];
  110.         double vx = n1.x - n2.x;
  111.         double vy = n1.y - n2.y;
  112.         double len = vx * vx + vy * vy;
  113.         if (len == 0) {
  114.             dx += Math.random();
  115.             dy += Math.random();
  116.         } else if (len < 100*100) {
  117.             dx += vx / len;
  118.             dy += vy / len;
  119.         }
  120.         }
  121.         double dlen = dx * dx + dy * dy;
  122.         if (dlen > 0) {
  123.         dlen = Math.sqrt(dlen) / 2;
  124.         n1.dx += dx / dlen;
  125.         n1.dy += dy / dlen;
  126.         }
  127.     }
  128.  
  129.     Dimension d = size();
  130.     for (int i = 0 ; i < nnodes ; i++) {
  131.         Node n = nodes[i];
  132.         if (!n.fixed) {
  133.         n.x += Math.max(-5, Math.min(5, n.dx));
  134.         n.y += Math.max(-5, Math.min(5, n.dy));
  135.         //System.out.println("v= " + n.dx + "," + n.dy);
  136.         if (n.x < 0) {
  137.             n.x = 0;
  138.         } else if (n.x > d.width) {
  139.             n.x = d.width;
  140.         }
  141.         if (n.y < 0) {
  142.             n.y = 0;
  143.         } else if (n.y > d.height) {
  144.             n.y = d.height;
  145.         }
  146.         }
  147.         n.dx /= 2;
  148.         n.dy /= 2;
  149.     }
  150.     repaint();
  151.     }
  152.  
  153.     Node pick;
  154.     boolean pickfixed;
  155.     Image offscreen;
  156.     Dimension offscreensize;
  157.     Graphics offgraphics;
  158.     
  159.  
  160.     final Color fixedColor = Color.red;
  161.     final Color selectColor = Color.pink;
  162.     final Color edgeColor = Color.black;
  163.     final Color nodeColor = new Color(250, 220, 100);
  164.     final Color stressColor = Color.gray;
  165.     final Color arcColor1 = Color.black;
  166.     final Color arcColor2 = Color.pink;
  167.     final Color arcColor3 = Color.red;
  168.  
  169.     public void paintNode(Graphics g, Node n, FontMetrics fm) {
  170.     int x = (int)n.x;
  171.     int y = (int)n.y;
  172.     g.setColor((n == pick) ? selectColor : (n.fixed ? fixedColor : nodeColor));
  173.     int w = fm.stringWidth(n.lbl) + 10;
  174.     int h = fm.getHeight() + 4;
  175.     g.fillRect(x - w/2, y - h / 2, w, h);
  176.     g.setColor(Color.black);
  177.     g.drawRect(x - w/2, y - h / 2, w-1, h-1);
  178.     g.drawString(n.lbl, x - (w-10)/2, (y - (h-4)/2) + fm.getAscent());
  179.     }
  180.  
  181.     public synchronized void update(Graphics g) {
  182.     Dimension d = size();
  183.     if ((offscreen == null) || (d.width != offscreensize.width) || (d.height != offscreensize.height)) {
  184.         offscreen = createImage(d.width, d.height);
  185.         offscreensize = d;
  186.         offgraphics = offscreen.getGraphics();
  187.         offgraphics.setFont(getFont());
  188.     }
  189.  
  190.     offgraphics.setColor(getBackground());
  191.     offgraphics.fillRect(0, 0, d.width, d.height);
  192.     for (int i = 0 ; i < nedges ; i++) {
  193.         Edge e = edges[i];
  194.         int x1 = (int)nodes[e.from].x;
  195.         int y1 = (int)nodes[e.from].y;
  196.         int x2 = (int)nodes[e.to].x;
  197.         int y2 = (int)nodes[e.to].y;
  198.         int len = (int)Math.abs(Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) - e.len);
  199.         offgraphics.setColor((len < 10) ? arcColor1 : (len < 20 ? arcColor2 : arcColor3)) ;
  200.         offgraphics.drawLine(x1, y1, x2, y2);
  201.         if (stress) {
  202.         String lbl = String.valueOf(len);
  203.         offgraphics.setColor(stressColor);
  204.         offgraphics.drawString(lbl, x1 + (x2-x1)/2, y1 + (y2-y1)/2);
  205.         offgraphics.setColor(edgeColor);
  206.         }
  207.     }
  208.  
  209.     FontMetrics fm = offgraphics.getFontMetrics();
  210.     for (int i = 0 ; i < nnodes ; i++) {
  211.         paintNode(offgraphics, nodes[i], fm);
  212.     }
  213.  
  214.     g.drawImage(offscreen, 0, 0, null);
  215.     }
  216.  
  217.     public synchronized boolean mouseDown(Event evt, int x, int y) {
  218.     double bestdist = Double.MAX_VALUE;
  219.     for (int i = 0 ; i < nnodes ; i++) {
  220.         Node n = nodes[i];
  221.         double dist = (n.x - x) * (n.x - x) + (n.y - y) * (n.y - y);
  222.         if (dist < bestdist) {
  223.         pick = n;
  224.         bestdist = dist;
  225.         }
  226.     }
  227.     pickfixed = pick.fixed;
  228.     pick.fixed = true;
  229.     pick.x = x;
  230.     pick.y = y;
  231.     repaint();
  232.     return true;
  233.     }
  234.  
  235.     public synchronized boolean mouseDrag(Event evt, int x, int y) {
  236.     pick.x = x;
  237.     pick.y = y;
  238.     repaint();
  239.     return true;
  240.     }
  241.  
  242.     public synchronized boolean mouseUp(Event evt, int x, int y) {
  243.     pick.x = x;
  244.     pick.y = y;
  245.     pick.fixed = pickfixed;
  246.     pick = null;
  247.     
  248.     repaint();
  249.     return true;
  250.     }
  251.  
  252.     public void start() {
  253.     relaxer = new Thread(this);
  254.     relaxer.start();
  255.     }
  256.     public void stop() {
  257.     relaxer.stop();
  258.     }
  259. }
  260.  
  261. public class graph extends Applet {
  262.     GraphPanel panel;
  263.  
  264.     public void init() {
  265.     setLayout(new BorderLayout());
  266.  
  267.     panel = new GraphPanel(this);
  268.     add("Center", panel);
  269.     Panel p = new Panel();
  270.     add("South", p);
  271.     p.add(new Button("Scramble"));
  272.     p.add(new Button("Shake"));
  273.     p.add(new Checkbox("Stress"));
  274.     p.add(new Checkbox("Random"));
  275.  
  276.     String edges = getParameter("edges");
  277.     for (StringTokenizer t = new StringTokenizer(edges, ",") ; t.hasMoreTokens() ; ) {
  278.         String str = t.nextToken();
  279.         int i = str.indexOf('-');
  280.         if (i > 0) {
  281.         int len = 50;
  282.         int j = str.indexOf('/');
  283.         if (j > 0) {
  284.             len = Integer.valueOf(str.substring(j+1)).intValue();
  285.             str = str.substring(0, j);
  286.         }
  287.         panel.addEdge(str.substring(0,i), str.substring(i+1), len);
  288.         }
  289.     }
  290.     Dimension d = size();
  291.     String center = getParameter("center");
  292.     if (center != null){
  293.         Node n = panel.nodes[panel.findNode(center)];
  294.         n.x = d.width / 2;
  295.         n.y = d.height / 2;
  296.         n.fixed = true;
  297.     }
  298.     }
  299.  
  300.     public void start() {
  301.     panel.start();
  302.     }
  303.     public void stop() {
  304.     panel.stop();
  305.     }
  306.     public boolean action(Event evt, Object arg) {
  307.     if (arg instanceof Boolean) {
  308.         if (((Checkbox)evt.target).getLabel().equals("Stress")) {
  309.         panel.stress = ((Boolean)arg).booleanValue();
  310.         } else {
  311.         panel.random = ((Boolean)arg).booleanValue();
  312.         }
  313.         return true;
  314.     } 
  315.     if ("Scramble".equals(arg)) {
  316.         play(getCodeBase(), "audio/computer.au");
  317.         Dimension d = size();
  318.         for (int i = 0 ; i < panel.nnodes ; i++) {
  319.         Node n = panel.nodes[i];
  320.         if (!n.fixed) {
  321.             n.x = 10 + (d.width-20)*Math.random();
  322.             n.y = 10 + (d.height-20)*Math.random();
  323.         }
  324.         }
  325.         return true;
  326.     }
  327.     if ("Shake".equals(arg)) {
  328.         play(getCodeBase(), "audio/gong.au");
  329.         Dimension d = size();
  330.         for (int i = 0 ; i < panel.nnodes ; i++) {
  331.         Node n = panel.nodes[i];
  332.         if (!n.fixed) {
  333.             n.x += 80*Math.random() - 40;
  334.             n.y += 80*Math.random() - 40;
  335.         }
  336.         }
  337.         return true;
  338.     }
  339.     return false;
  340.     }
  341. }
  342.