import java.io.*; import java.util.*; import java.lang.Math.*; public class Flock { int space_radius = 10; int point_count = 31; int frame_count = 60; int object_size = 1; int max_speed = 50; double max_jump = 1.1; vector3D position[][] = null; vector3D velocity[][] = null; private void collision( int f ) { // for each point for( int p = 1; p < point_count; p++ ) { // collision detector for( int i = 0; i < point_count; i++ ) { if( i != p ) { vector3D v = new vector3D( position[f][i] ); v.sub( position[f][p] ); if( v.length() < object_size * 2 ) { v.normalize(); v.mul( object_size * 2 ); position[f][p].set( position[f][i] ); position[f][p].sub( v ); } } } } } private void speeding( int f ) { // for each point for( int p = 1; p < point_count; p++ ) { if( velocity[f][p].length() > max_speed ) { // clean up velocity velocity[f][p].normalize(); velocity[f][p].mul( max_speed ); } } } public Flock() { try { Random R = new Random( 1000 ); position = new vector3D[frame_count*2][point_count]; velocity = new vector3D[frame_count*2][point_count]; // output file FileOutputStream file = new FileOutputStream( "flock.inc" ); BufferedOutputStream buf = new BufferedOutputStream( file ); PrintStream out = new PrintStream( buf ); // first point is target for( int f = 0; f < frame_count * 2; f++ ) { /* // round and round in a big circle double angle = ( ( (double) f / frame_count ) * 2.0 * Math.PI ) + Math.PI; System.out.println( "angle = " + angle ); position[f][0] = new vector3D( Math.sin( angle ) * space_radius, 0, Math.cos( angle ) * space_radius ); velocity[f][0] = new vector3D( Math.sin( angle + ( Math.PI / 2 ) ) * space_radius, 0, Math.cos( angle + ( Math.PI / 2 ) ) * space_radius ); */ /* // straight line position[f][0] = new vector3D( -frame_count + f * 2, 1, 0 ); velocity[f][0] = new vector3D( 1, 1, 1 ); */ // sine wave position[f][0] = new vector3D( f, 1, 5 * Math.sin( ( (float) f / frame_count ) * 2 * Math.PI ) ); velocity[f][0] = new vector3D( 1, 1, 1 ); /* // dog leg if( f < frame_count / 2 ) position[f][0] = new vector3D( -frame_count + f * 2, 0, frame_count - f * 2 ); else position[f][0] = new vector3D( -frame_count + f * 2, 0, 0 ); velocity[f][0] = new vector3D( 1, 1, 1 ); */ } // initialize for( int p = 1; p < point_count; p++ ) { // set initial positions double px = R.nextDouble() - 0.5; double py = Math.abs( R.nextDouble() - 0.5 ); double pz = R.nextDouble() - 0.5; position[0][p] = new vector3D( px, py, pz ); position[0][p].mul( space_radius * 2 ); position[0][p].add( position[0][0] ); position[0][p].sub( new vector3D( space_radius, 0, 0 ) ); // set initial velocities double vx = R.nextDouble() - 0.5; double vy = R.nextDouble() - 0.5; double vz = R.nextDouble() - 0.5; velocity[0][p] = new vector3D( vx, vy, vz ); velocity[0][p].mul( 100 ); } // check collisions collision( 0 ); speeding( 0 ); // for each frame for( int f = 1; f < frame_count * 2; f++ ) { // move towards target for( int p = 1; p < point_count; p++ ) { // start with previous velocity position[f][p] = new vector3D( position[f-1][p] ); velocity[f][p] = new vector3D( velocity[f-1][p] ); // first point is main attractor vector3D v = new vector3D( position[f][0] ); v.sub( position[f][p] ); velocity[f][p].add( v ); } // add some random noise to velocities for( int p = 1; p < point_count; p++ ) { double dx = R.nextDouble() - 0.5; double dy = R.nextDouble() - 0.5; double dz = R.nextDouble() - 0.5; vector3D v = new vector3D( dx, dy, dz ); v.mul( 0.5 ); v.add( 1.0 ); velocity[f][p].mul( v ); } // update positions for( int p = 1; p < point_count; p++ ) { // update position position[f][p] = new vector3D( position[f-1][p] ); vector3D v = new vector3D( velocity[f][p] ); if( v.length() > max_jump ) { v.normalize(); v.mul( max_jump ); } position[f][p].add( v ); } // collision detector collision( f ); speeding( f ); } // last frames are a kludge for( int f = 0; f < 10; f++ ) { // move towards target for( int p = 1; p < point_count; p++ ) { // distance from target in first frame vector3D v = new vector3D( position[frame_count][0] ); v.sub( position[frame_count][p] ); double xx = v.x; // compute new target position v = new vector3D( ( frame_count * 2 ) - xx, position[frame_count][p].y, position[frame_count][p].z ); // subtract starting position v.sub( position[(frame_count*2)-10][p] ); // move 10% per frame v.mul( f * 0.1 ); // add back starting position v.add( position[(frame_count*2)-10][p] ); // set updated position position[(frame_count*2)-10+f][p] = new vector3D( v ); // velocity is just weighted average v = new vector3D( velocity[frame_count][p] ); v.sub( velocity[(frame_count*2)-10+f][p] ); v.mul( f * 0.1 ); v.add( velocity[(frame_count*2)-10+f][p] ); velocity[(frame_count*2)-10+f][p] = new vector3D( v ); } } // general information System.out.println( "WRITING..." ); out.println( "// GENERATED FLOCKING FILE" ); out.println( "" ); out.println( "#declare point_count = " + point_count + ";" ); out.println( "#declare frame_count = " + frame_count + ";" ); out.println( "#declare space_radius = " + space_radius + ";" ); out.println( "" ); out.println( "#declare position = array[" + frame_count + "][" + point_count + "][2]" ); out.println( "{" ); // for each frame for( int f = 0; f < frame_count; f++ ) { out.println( " { // frame " + f ); // for each point for( int p = 0; p < point_count; p++ ) out.println( " { " + position[f+frame_count][p] + ", " + velocity[f+frame_count][p] + " }" ); out.println( " }," ); } out.println( "}" ); out.flush(); out.close(); System.out.println( "...DONE" ); } catch( Exception ex ) { System.out.println( ex.getMessage() ); ex.printStackTrace(); } } public static void main( String[] args ) { Flock f = new Flock(); } }