/* Statics dynamic model Derived from AnimTemplate.java and Simul.java Chris Davis March 2006 */ import java.awt.*; import java.util.*; import java.awt.event.*; import java.lang.Math; public class Statics2D extends java.applet.Applet implements Runnable { private Thread testThread = null; Dimension appletSize; int count, xmax, ymax; Image offImage; Graphics offGraphics; Color colorpalette[] = new Color[10]; int xpoints[] = new int[4]; int ypoints[] = new int[4]; int x1, x2, y1, y2, paletteindex; int p1, p2, p3, p4; boolean go = false; int nbodies = 1000; public SBody b[] = new SBody[ nbodies ]; public STie t[] = new STie[ nbodies ]; double DT = 0.005; double time = 0; public void init() { int m, n, r, c; this.enableEvents( AWTEvent.MOUSE_EVENT_MASK ); appletSize = this.getSize(); xmax = appletSize.width; // graphics width ymax = appletSize.height; // graphics height n = 0; for ( r = 1; r <= 3; r++ ) { for ( c = 1; c <= 20; c++ ) { b[n] = new SBody( (double)(r * 10), (double)(c * 10), 1.0 ); n++; } } b[0].fix_xy(); b[20].fix_xy(); b[40].fix_xy(); SBody.nbodies = n; System.out.println( n ); n = 0; for ( r = 1; r <= 3; r++ ) { for ( c = 1; c <= 20; c++ ) { m = (r-1) * 20 + (c-1); if ( (c < 40) && (c != 20) ) { t[n] = new STie( n, b[m], b[m+1] ); n++; } if ( r < 3 ) { t[n] = new STie( n, b[m], b[m+20] ); n++; } if ( (m < 39) && (m != 19) ) { t[n] = new STie( n, b[m], b[m+21] ); n++; } if ( (m < 40) && (m != 0) && (m != 20) ) { t[n] = new STie( n, b[m], b[m+19] ); n++; } } } STie.nties = n; System.out.println( n ); setBackground(Color.white); count=1; x1 = 0; x2= 0; y1 = 100; y2 = 100; p1 = 3; p2 = 2; p3 = 4; p4 = 1; offImage = createImage( xmax, ymax ); offGraphics = offImage.getGraphics(); colorpalette[0] = new Color( 100, 100, 100 ); colorpalette[1] = new Color( 100, 255, 255 ); colorpalette[2] = new Color( 200, 255, 100 ); colorpalette[3] = new Color( 255, 255, 000 ); colorpalette[4] = new Color( 000, 255, 255 ); colorpalette[5] = new Color( 100, 255, 000 ); colorpalette[6] = new Color( 255, 100, 255 ); colorpalette[7] = new Color( 100, 100, 255 ); colorpalette[8] = new Color( 100, 255, 100 ); colorpalette[9] = new Color( 255, 200, 100 ); } public void start() { if (testThread == null) { testThread = new Thread(this, "Test1"); testThread.start(); } } public void processMouseEvent( MouseEvent e) { int n; if ( e.getID() == MouseEvent.MOUSE_ENTERED ) { go = false; } else if ( e.getID() == MouseEvent.MOUSE_EXITED ) { go = true; } else if ( e.getID() == MouseEvent.MOUSE_RELEASED ) { n = (int)( (double)SBody.nbodies * Math.random() ); b[n].x = b[n].x + 0.2; b[n].y = b[n].y + 0.2; go = true; } else super.processMouseEvent(e); } public void run() { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); Thread myThread = Thread.currentThread(); while (testThread == myThread) { if ( go ) { engine( DT ); repaint(); count++; } try { Thread.sleep(10); } catch (InterruptedException e){ } } } // calculate body motions public void engine( double dt ) { int n; SBody.zero_energy(); STie.zero_energy(); // Zero body accelerations, add gravitational acceleration for ( n = 0; n < SBody.nbodies; n++ ) { b[n].xxx = 0.0; b[n].yyy = 0.0; b[n].add_gravitational_acceleration(); } // calculate new body elastic accelerations for ( n = 0; n < STie.nties; n++ ){ t[n].add_elastic_accelerations( b ); t[n].potential_energy(); } // calculate new body speeds for ( n = 0; n < SBody.nbodies; n++ ){ b[n].xx = b[n].xx + b[n].xxx * dt; // new x velocity b[n].yy = b[n].yy + b[n].yyy * dt; // new x velocity b[n].kinetic_energy(); } // calculate new body locations after time dt. for ( n = 0; n < SBody.nbodies; n++ ){ if ( !b[n].fixed ) { b[n].x = b[n].x + b[n].xx * dt; // new x b[n].y = b[n].y + b[n].yy * dt; // new y } } // increase K for ( n = 0; n < STie.nties; n++ ){ t[n].change_K( dt ); } time = time + DT; // System.out.println( "76: " + (float)t[76].tension + " " + (float)t[76].tie_length + " " + (float)t[76].tie_free_length ); // System.out.println( "9: " + (float)t[9].tension + " " + (float)t[9].tie_length + " " + (float)t[9].tie_free_length ); } public void paint(Graphics g) { update(g); } public void update(Graphics g) { int n, tt, k; int x0, x1, y0, y1, offset; double scale; String s; tt = 1; k = 1; scale = 2.0; offset = 10; /* draw something into offGraphics*/ offGraphics.setPaintMode(); offGraphics.setColor( Color.white ); offGraphics.fillRect( 0, 0, xmax, ymax ); for ( n = 0; n < STie.nties; n++ ) { if ( t[n].tension < 0 ) { offGraphics.setColor( Color.blue ); } else { offGraphics.setColor( Color.red ); } if ( k > 0 ) { x0 = offset + (int)(t[n].b1.x * scale); y0 = offset + (int)(t[n].b1.y * scale); x1 = offset + (int)(t[n].b2.x * scale); y1 = offset + (int)(t[n].b2.y * scale); offGraphics.drawLine( x0, y0, x1, y1 ); } } for ( n = 0; n < SBody.nbodies; n++ ) { x0 = offset + (int)(b[n].x * scale); y0 = offset + (int)(b[n].y * scale); if ( b[n].fixed ) { offGraphics.setColor( Color.green ); } else { offGraphics.setColor( Color.black ); } offGraphics.fillOval( x0-1, y0-1, 3, 3 ); } offGraphics.setColor( Color.black ); s = "" + "Time " + (int)time + " s "; s = s + " DT " + (float)DT; s = s + " k.e. " + (float)SBody.net_ke; s = s + " p.e. " + (float)STie.net_pe; offGraphics.drawString( s , 2, 12 ); /* draw offGraphics into Graphics */ g.drawImage( offImage, 0, 0, this ); } public void stop() { testThread = null; } } // Body class variables, plus constructors and methods class SBody { static int nbodies; static double net_ke; // net kinetic energy of bodies static double net_pe; // net potential energy of bodies public int num; // unique number n public String name; // body name public double x; // x locatiom m public double y; // y location m public boolean fixed; // x-y location fixed public double xx; // x velocity m/s public double yy; // y velocity m/s public double xxx; // x acceleration m/s2 public double yyy; // y acceleration m/s2 public double v; // speed m/s public double ke; // kinetic energy public double m; // body mass kg public Color colour; // body colour // explicit default constructor public SBody() { } public SBody( double y, double x, double m ) { this.x = x; this.y = y; this.m = m; this.fixed = false; } // fix body location public void fix_xy() { this.fixed = true; } // reset kinetic and potential energy to zero static void zero_energy() { net_ke = 0.0; net_pe = 0.0; } // Reset acceleration to zero public void zero_acceleration() { this.xxx = 0; this.yyy = 0; } // Calculate accelerations due to gravitational attraction. public void add_gravitational_acceleration() { this.yyy = this.yyy + 9.81; } // Calculate new body speed after time t public void new_speed( double t ){ this.xx = this.xx + this.xxx * t; // new x velocity this.yy = this.yy + this.yyy * t; // new y velocity } // Calculate new body position after time t public void new_position( double t ){ this.x = this.x + this.xx * t; // new x this.y = this.y + this.yy * t; // new y } // Calculate speed and kinetic energy public void kinetic_energy() { this.v = Math.sqrt( this.xx * this.xx + this.yy * this.yy ); this.ke = 0.5 * this.m * this.v * this.v; net_ke = net_ke + this.ke; } } // Tie class variables and methods class STie { static int nties; // number of ties static double net_pe; // net potential energy public int num; // tied body number public SBody b1; // end body 1 public SBody b2; // end body 2 public double tie_length; // tie current length public double tie_free_length; // tie free length public double tie_max_length; // tie maximum length public double tie_K; // tie spring constant public double final_tie_K; // final tie spring constant public double tie_K_rate; // tie spring constant increase rate public double tension; // tie tension public double extension; // tie extension public double pe; // tie potential energy public int tense_only = 1; // tie types public int tense_and_compress = 2; // .. public int compress_only = 3; // .. public int tie_type = tense_only; // tie type in operation public Color tie_colour; // tie colour public double bx; // base x location public double by; // base y location // explicit default constructor public STie() { } // tie constructor. public STie( int n, SBody n1, SBody n2 ){ double lx, ly; this.num = n; this.b1 = n1; this.b2 = n2; lx = this.b1.x - this.b2.x; ly = this.b1.y - this.b2.y; this.tie_length = Math.sqrt( lx * lx + ly * ly ); this.tie_free_length = this.tie_length; this.tie_colour = new Color( 80, 80, 80 ); this.tie_max_length = 1.5 * this.tie_free_length; this.tie_K = 0.0; this.final_tie_K = 7000.0; this.tie_K_rate = this.final_tie_K / 10000.0; this.set_final_tie_K(); // set final K } // set tie K to final K public void set_final_tie_K() { this.tie_K_rate = this.final_tie_K; } // reset potential energy to zero static void zero_energy() { net_pe = 0.0; } // Calculate accelerations due to tie tension/compression. public void add_elastic_accelerations( SBody b[] ) { double lx, ly, r, dl, f; lx = this.b1.x - this.b2.x; ly = this.b1.y - this.b2.y; r = Math.sqrt(lx * lx + ly * ly); // tie length this.extension = this.tie_free_length - r; // tie extension this.tie_length = r; // new tie length // if ( this.extension > 0 ) { this.extension = 0; } // tension only (for now) f = this.tie_K * this.extension; // force = K.dl this.tension = f; // acceleration = force / mass this.b1.xxx = this.b1.xxx + (f * lx)/(r * this.b1.m); // x component of accel this.b1.yyy = this.b1.yyy + (f * ly)/(r * this.b1.m); // y component of accel this.b2.xxx = this.b2.xxx - (f * lx)/(r * this.b2.m); // x component of accel this.b2.yyy = this.b2.yyy - (f * ly)/(r * this.b2.m); // y component of accel } // calculate spring potential energy: 0.5.k.e^2 public void potential_energy() { this.pe = 0.5 * this.tie_K * this.extension * this.extension; net_pe = net_pe + this.pe; } // spring constants increase from zero to some final value public void change_K( double dt ) { if ( this.tie_K >= final_tie_K ) { this.tie_K = final_tie_K; } else { this.tie_K = this.tie_K + tie_K_rate * dt; } } // set tie colour. Increasing blue with tension, red with compression. // uses length rather than calculated tension. public void set_tie_colour( int vt ) { double f; int i = 55; if ( vt == 2 ){ if ( this.tie_length > this.tie_free_length ) { f = ( this.tie_length - this.tie_free_length ) / ( this.tie_max_length - this.tie_free_length ); f = Math.pow( f, 0.333 ); if ( f > 1 ) { f = 1; } this.tie_colour = new Color( i, i, i + (int)(f * (255-i)) ); } else { f = ( this.tie_free_length - this.tie_length ) / this.tie_free_length; f = Math.pow( f, 0.333 ); if ( f > 1 ) { f = 1; } this.tie_colour = new Color( i + (int)(f * (255-i)), i, i ); } } if ( vt == 1 ) { if ( this.tie_K > 0 ) { this.tie_colour = new Color( 80, 80, 80 ); } else { this.tie_colour = new Color( 0, 0, 0 ); } } if ( vt== 0 ) { this.tie_colour = new Color( 0, 0, 0 ); } } }