*
* Copyright (C) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
* @Modified 96/04/24 Jim Hagen: Changed StressColor
*
* Permission To Use, Copy, Modify, and Distribute this Software
* AND ITS Documentation for non-Commercial or Commercial Purposes and
* WITHOUT Fee Is hereby granted.
* Please refer to the file http://java.sun.com/copy_trademarks.html
* for further important copyright and trademark information and to to
* http://java.sun.com/Licensing.html for further important licensing
* Information for The Java (TM) Technology.
*
* Sun Makes no representations or warranties about the suitability of
* The Software, Either Express Or Implied, Including But Not Limited
* To the import Warranties of Merchantability, Fitness for a
* Particular Purpose, or Non-Infringement. Sun Shall Not Be Liable for
* Any Damages Suffered by licensee as a result of usufactage, modify or
* Distributing this Software Or ITS DeriVATIVES.
*
* This Software Is Not Designed or Intended for Use or Resale as On-line
* Control Equipment in Hazardous Environments Requiring Fail-Safe
* Performance, Such as in The Operation of Nuclear Facilities, Aircraft
* Navigation or Communication Systems, Air Traffic Control, Direct Life
* Support Machines, Or Weapons Systems, in which the failure of the
* Software Could Lead Directly to Death, Personal Injury, or Severe
* Physical or Environmental Damage ("High Risk Activities"). Sun
* Specify or Implied Warranty Of Fitness for
* High risk activities.
* /
Import java.util. *;
Import java.awt. *;
IMPORT JAVA.Applet.applet;
Class node {
Double X;
Double Y;
Double DX;
Double Dy;
Boolean fixed;
String lbl;
}
Class Edge {Int from
Int to;
Double Len;
}
Class GraphPanel Extends Panel IMPLEMENTS Runnable {
Graph graph;
Int nnodes;
Node nodes [] = new node [100];
Int Nedges;
Edge edges [] = new edge [200];
Thread Relaxer;
Boolean stress;
Boolean Random;
GraphPanel (Graph graph) {
THIS.GRAPH = GRAPH;
}
INT FINDNODE (STRING LBL) {
For (int i = 0; i IF (nodes [i] .lbl.equals (lbl)) { Return I; } } Return AddNode (LBL); } Int AddNode (String LBL) { Node n = new node (); N.x = 10 380 * math.random (); n.y = 10 380 * math.random (); n.lbl = lbl; Nodes [nnotes] = n; Return nnodes ; } Void Adde (String from, String to, Int Len) { Edge E = New Edge (); E.FROM = FindNode (from); e.to = findnode (to); E.1; EDGES [NEDGES ] = E; } Public void run () { While (true) { Relax (); IF (math.random () <0.03)) { Node n = nodes [(int) (Math.random () * nnodes)]; IF (! n.fixed) { N.X = 100 * math.random () - 50; N.Y = 100 * math.random () - 50; } Graph.play (graph.getcodebase (), "Audio / Drip.au"); } Try { Thread.sleep (100); } catch (interruptedexception e) { Break; } } } SYNCHRONIZED VOID RELAX () { For (int i = 0; i Edge E = Edges [I]; Double vx = nodes [e.to] .x - nodes [e.from] .x; Double Vy = nodes [e.to] .y - nodes [e.from] .y; Double Len = Math.SQRT (VX * VX VY * VY); Double f = (Edges [i] .len - len) / (len * 3); Double DX = f * vx; Double DY = f * Vy; Nodes [e.to] .dx = DX; NODES [E.to] .dy = DY; Nodes [E.FROM] .dx = -dx; Nodes [E.FROM] .dy = -dy; } For (int i = 0; i Double dx = 0; Double DY = 0; For (int J = 0; j IF (i == j) { CONTINUE; } Node N2 = NODES [J]; Double vx = n1.x - n2.x; Double Vy = n1.y - n2.y; Double Len = VX * VX VY * VY; IF (len == 0) { DX = math.random (); DY = math.random (); } else IF (len <100 * 100) { DX = VX / LEN; DY = VY / LEN; } } Double Dlen = DX * DX DY * DY; IF (DLEN> 0) { Dlen = Math.sqRT (DLEN) / 2; N1.DX = DX / DLEN; N1.DY = DY / DLEN; } } Dimension D = Size (); For (int i = 0; i Node n = nodes [i]; IF (! n.fixed) { N.X = math.max (-5, math.min (5, n.dx)); n.y = math.max (-5, math.min (5, n.dy)); //System.out.println ("v= " n.dx ", " n.dy); IF (n.x <0) { N.x = 0; } else if (n.x> d.width) { N.x = d.width; } IF (n.y <0) { n.y = 0; } else if (n.y> d.height) { n.y = d.height; } } n.dx / = 2; n.dy / = 2; } Repaint (); } Node Pick; Boolean pickfixed; Image offscreen; Dimension OFFSCREENSIZE; Graphics offgraphics; Final Color FixedColor = Color.Red; Final Color SelectColor = color.pink; Final Color EdgeColor = Color.Black; Final Color NodeColor = New Color (250, 220, 100); Final Color StressColor = color.darkgray; Final Color Arccolor1 = Color.Black; Final Color Arccolor2 = color.pink; Final Color Arccolor3 = color.red; Public void PainTNode (Graphics G, Node N, FontMetrics FM) { INT x = (int) n.x; INT Y = (int) n.y; g.setcolor ((n == pick)? SELECTCOLOR: (N.FIXED? FixedColor: NodeColor); INT W = fm.stringwidth (n.lbl) 10; INT H = fm.getHeight () 4; G.FillRect (x - w / 2, y - h / 2, w, h); g.setcolor (color.ble); g.drawRect (x - w / 2, y - h / 2, W-1, h-1); g.drawstring (N.LBL, X - (W-10) / 2, (Y - (H-4) / 2) fm.getascent ()); } Public Synchronized Void Update (Graphics G) { Dimension D = Size (); IF ((Offscreen == Null) || (D.Width! = OFFSCREENSIZE.WIDTH) || (D.Height! = OFFSCREENSIZE.HEIGHT)) { OFFSCREEN = CREATEIMAGE (D.Width, D.HeiGHT); OFFSCREENSIZE = D; OFFRAPHICS = OFFSCREEN.GRAPHICS (); OFFGRAPHICS.SETFONT (getFont ()); } Offgraphics.SetColor (GetBackground ()); Offgraphics.FillRect (0, 0, D. Width, D.HeiGHT); For (int i = 0; i Edge E = Edges [I]; INT x1 = (int) Nodes [E.FROM] .x; INT Y1 = (int) Nodes [E.FROM] .y; INT x2 = (int) Nodes [e.to] .x; INT Y2 = (int) nodes [e.to] .y; INT LEN = (int) math.abs (Math.SQRT ((x1-x2) * (x1-x2) (Y1-Y2) * (Y2)) - E.LEN); Offgraphics.SetColor ((Len <10)? ArcColor1: (Len <20? Arccolor2: ArcColor3)); OFFGRAPHICS.DRAWLINE (X1, Y1, X2, Y2); IF (stress) { String lbl = String.Valueof (len); Offgraphics.SetColor (stresscolor); OFFGRAPHICS.DRAWSTRING (LBL, X1 (X2-X1) / 2, Y1 (Y2-Y1) / 2); OFFRAPHICS.SETCOLOR (EdgeColor); } } FontMetrics FM = OFFGRAPHICS.GETFONTMETRICS (); For (int i = 0; i PainTnode (Offgraphics, Nodes [i], fm); } g.drawimage (OFFSCREEN, 0, 0, NULL); } Public Synchronized Boolean MouseDown (Event EVT, INT X, INT Y) { Double BestDist = Double.max_Value; For (int i = 0; i Double Dist = (N.X - x) * (N.x - x) (N.Y - Y) * (N.Y - Y); IF (dist PICK = N; BestDist = DIST; } } Pickfixed = pick.fixed; Pick.fixed = true; Pick.x = x; Pick.y = y; Repaint (); Return True; } Public Synchronized Boolean MouseDrag (Event EVT, INT X, INT Y) { Pick.x = x; Pick.y = y; Repaint (); Return True; } Public Synchronized Boolean Mouseup (Event EVT, INT X, INT Y) { Pick.x = x; Pick.y = y; Pick.fixed = pickfixed; Pick = NULL; Repaint (); Return True; } Public void start () { Relaxer = new thread (this); Relaxer.start (); } Public void stop () { Relaxer.stop (); } } Public class graph extends applet { GraphPanel Panel; Public void init () { SetLayout (New BorderLayout ()); Panel = new graphpanel (this); Add ("Center", Panel; PANEL P = new panel (); Add ("South", P); P.Add (New Button)); P.Add (New Button ("shake"); P.Add (New Checkbox ("stress"); P.Add (New Checkbox ("Random"); String Edges = getParameter ("Edges"); For (StringTokenizer T = New StringTokenizer (EDGES, ","); T.haSmoreToKens ();) { String str = T.NEXTTOKEN (); INT i = str.indexof ('-'); IF (i> 0) { INT LEN = 50; INT j = str.indexof ('/'); IF (j> 0) { Len = Integer.Valueof (Str.Substring (J 1)). INTVALUE (); Str = str.substring (0, j); } Panel.addedge (Str.Substring (0, i), Str.Substring (i 1), len); } } Dimension D = Size (); String center = getParameter ("center"); IF (center! = null) { Node n = panel.nodes [panel.findnode (center)]; n.x = d.width / 2; n.y = d.height / 2; n.fixed = true; } } Public void start () { panel.start (); } Public void stop () { panel.stop (); } Public Boolean Action (Event EVT, Object Arg) { IF (arg instanceof boolean) { IF ((CheckBox). Getlabel (). Equals ("stress")) { Panel.stress = ((Boolean) arg) .BooleanValue (); } else { Panel.random = ((Boolean) arg) .BooleanValue (); } Return True; } IF ("scramble" .equals (arg)) { Play (getCodeBase (), "Audio / Computer.au"); Dimension D = Size (); For (int i = 0; i Node n = panel.nodes [i]; IF (! n.fixed) { N.x = 10 (d.width-20) * math.random (); n.y = 10 (D.Height-20) * math.random (); } } Return True; } IF ("Shake" .equals (arg)) { Play (getCodeBase (), "Audio / Gong.au"); Dimension D = Size (); For (int i = 0; i Node n = panel.nodes [i]; IF (! n.fixed) { N.X = 80 * math.random () - 40; N.Y = 80 * math.random () - 40; } } Return True; } Return False; } }