// // FastMech.java // FastMech // import java.applet.Applet; import java.util.*; import java.awt.*; import java.lang.Math; public class FastMech extends Applet { // x's and y's in the same array. Numbering from zero. // x's first (evens), then y's (odds). // Relative to the index i of the beginning of a cell's // numbers, the corners of a cell get these coordinates: // ( xy[i+2], xy[i+3] ) --- ( xy[i+6], xy[i+7] ) // | | // | | // | | // | | // ( xy[ i ], xy[i+1] ) --- ( xy[i+4], xy[i+5] ) // These are all double because float requires casting! double xy[]; // x and y components of position double min_x = 0.0; double max_x = 0.0; double min_y = 0.0; double max_y = 0.0; double mxy[]; // x and y components of momentum double old_mxy[]; // used by local_drag() double fxy[]; // x and y components of force double A[][]; // square matrix set up so that A * xy = fxy int n_cells; double xf, xc, yf, yc; // scaling constants for drawing Random random = new Random(); public void init_cells( int n_cells ) { xy = new double [ 4 + 4 * n_cells ]; mxy = new double [ xy.length ]; old_mxy = new double [ xy.length ]; fxy = new double [ xy.length ]; A = new double [ xy.length ] [ xy.length ]; mxy = new double [ 4 + 4 * n_cells ]; this.n_cells = n_cells; xy[ 0 ] = 0.0; xy[ 1 ] = 0.0; xy[ 2 ] = 0.0; xy[ 3 ] = 1.0; for( int i = 0; i < n_cells; i++ ) { xy[ i*4 + 4 ] = ( i + 1 ) * 1.0; xy[ i*4 + 5 ] = 0.0; xy[ i*4 + 6 ] = ( i + 1 ) * 1.0; xy[ i*4 + 7 ] = 1.0; } } public void init( ) { init_cells( 30 ); } public void draw_wall( Graphics g, int i, int j ) { g.drawLine( (int) ( xy[ i ]*xf+xc ), (int) ( xy[i+1]*yf+yc ), (int) ( xy[ j ]*xf+xc ), (int) ( xy[j+1]*yf+yc ) ); } public void paint( Graphics g ) { double max; min_x += ( max_x - min_x ) / 1000.0; max_x -= ( max_x - min_x ) / 999.0; min_y += ( max_y - min_y ) / 1000.0; max_y -= ( max_y - min_y ) / 999.0; for( int i = 2; i < xy.length; i += 2 ) { if( xy[ i ] < min_x ) min_x = xy[ i ]; if( xy[ i ] > max_x ) max_x = xy[ i ]; if( xy[i+1] < min_y ) min_y = xy[i+1]; if( xy[i+1] > max_y ) max_y = xy[i+1]; } if( max_x - min_x > max_y - min_y ) max = max_x - min_x; else max = max_y - min_y; // Assuming the window is 400 x 400... xf = 320.0 / max; yf = -xf; // Java AWT's y is upside-down; xc = 200.5 - xf * .5 * ( min_x + max_x ); yc = 200.5 - yf * .5 * ( min_y + max_y ); draw_wall( g, 0, 2 ); for( int i = 0; i <= xy.length - 8; i += 4 ) { draw_wall( g, i, i + 4 ); draw_wall( g, i + 4, i + 6 ); draw_wall( g, i + 6, i + 2 ); } recalc(); repaint(); } // Calculate linear approximations to the two-way // force effects of a spring // as a function of the end coordinates. void calc_spring( double A[][], double fxy[], double xy[], int i, int j, double preferred_len ) { // These springs will have a constant stiffness // regardless of preferred_len, because my head hurts. // That means the coefficients of the equations are // always the same. Always 1 and -1, actually. double xl = xy[ j ] - xy[ i ]; double yl = xy[j+1] - xy[i+1]; double len = Math.sqrt( xl * xl + yl * yl ); // What would xy[ j ] - xy[ i ], etc., like to be? double dx = xl * preferred_len / len; double dy = yl * preferred_len / len; // Add equations into A matrix and fxy vector: // Force on xy[i] = xy[j] - xy[i] - dx (etc.), so A[i][i] -= 1.0; A[i+1][i+1] -= 1.0; A[i][j] += 1.0; A[i+1][j+1] += 1.0; fxy[i] -= dx; fxy[i+1] -= dy; // Force on xy[j] = xy[i] - xy[j] + dx (etc.), so A[j][j] -= 1.0; A[j+1][j+1] -= 1.0; A[j][i] += 1.0; A[j+1][i+1] += 1.0; fxy[j] += dx; fxy[j+1] += dy; } // Calculate the positions -> forces matrix // based on some arbitrary physics for the cells. void calc_matrix( double A[][], double fxy[], double xy[] ) { for( int i = 0; i < fxy.length; i++ ) { fxy[ i ] = 0.0; for( int j = 0; j < fxy.length; j++ ) { A[ i ][ j ] = 0.0; } } double s3 = Math.sqrt( 3.0 ); // Each cell has a spring on each side, and // criss-cross truss springs so it doesn't flatten. calc_spring( A, fxy, xy, 0, 2, 1.0 ); for( int i = 0; i <= xy.length - 8; i += 4 ) { // i, i+2 spring is already calculated. calc_spring( A, fxy, xy, i, i+4, 2.0 ); calc_spring( A, fxy, xy, i, i+6, s3 ); calc_spring( A, fxy, xy, i+2, i+4, s3 ); calc_spring( A, fxy, xy, i+2, i+6, 1.0 ); calc_spring( A, fxy, xy, i+4, i+6, 1.0 ); } } // Matrix multiply using conventional names for the variables: // b coming in is the constants, going out is the results. // b += A * x void matrix_multiply_add( double A[][], double x[], double b[] ) { for( int i = 0; i < x.length; i++ ) { double row[] = A[i]; for( int j = 0; j < x.length; ) { b[ i ] += row[j] * x[j]; while( ++j < x.length && row[j] == 0.0 ); } } } // x1 = x1f * x1 + x2f * x2 void scaled_vector_add( double x1f, double x1[], double x2f, double x2[] ) { for( int i = 0; i < x1.length; i++ ) { x1[ i ] = x1f * x1[ i ] + x2f * x2[ i ]; } } /* void random_forces( double fxy[] ) { for( int i = 0; i < mxy.length; i++ ) { fxy[ i ] = ( random.nextInt( 32768 ) - 16383.5 ) / 100000.0; } } */ // Calculate two-way drag effect between points i & j. void pair_drag( double mxy[], double f, int i, int j ) { for( int k = 0; k < 2; k++ ) { double diffxy = ( old_mxy[j+k] - old_mxy[i+k] ) * f; mxy[i+k] += diffxy; mxy[j+k] -= diffxy; } } void local_drag( double mxy[], double f ) { System.arraycopy( mxy, 0, old_mxy, 0, mxy.length ); pair_drag( mxy, f, 0, 2 ); for( int i = 0; i <= mxy.length - 8; i += 4 ) { // i is the bottom-left corner. // pair_drag( mxy, f, i, i + 2 ) already done. pair_drag( mxy, f, i, i + 4 ); pair_drag( mxy, f, i + 2, i + 6 ); pair_drag( mxy, f, i + 4, i + 6 ); } } /* void print_equations( double A[][], double fxy[] ) { for( int i = 0; i < fxy.length; i++ ) { String str = ""; for( int j = 0; j < fxy.length; j++ ) { str = str + A[i][j] + " "; } System.out.println( str + "= " + fxy[ i ] ); } } */ void recalc( ) { calc_matrix( A, fxy, xy ); // print_equations( A, fxy ); matrix_multiply_add( A, xy, fxy ); // Calculate forces. // for( double f = .01; f < .1; f += .005 ) { // local_drag( mxy, f ); // } local_drag( mxy, .1 ); // random_forces( fxy ); scaled_vector_add( 1.0, mxy, .5, fxy ); scaled_vector_add( 1.0, xy, 1.0, mxy ); } public void destroy( ) { } }